1#!/usr/local/bin/wish8.6 -f
2# The next line is executed by /bin/sh, but not tcl \
3#exec wish "$0" -- $*
4
5## iSpin GUI -- http::/spinroot.com/
6## (c) 2010-2014 All Rights Reserved
7## This software is for educational purposes only.
8## No guarantee whatsoever is expressed or implied
9## by the distribution of this code.
10
11wm title . "ispin"
12wm geometry . 1200x600+20+20
13
14set xversion "iSpin Version 1.1.4 -- 27 November 2014"
15set version "Spin Version unknown";   # updated below
16set Unix 1;                           # updated below
17
18### Tools
19	set SPIN    spin   ;# essential
20	set CC      gcc    ;# essential
21	set DOT     dot    ;# recommended, for automata view
22#	set DOT     "C:/Program\ Files\ \(x86\)/Graphviz2.36/bin/dot"
23	set SWARM   swarm  ;# optional, for swarm verification panel
24	set CURL    curl   ;# optional, for version check information
25
26	set CC_alt1 gcc-4
27	set CC_alt2 gcc-3
28	set RM      "rm -f"
29	set KILL    "kill -2"
30
31	## check if we have the right version of Spin
32	if {[auto_execok $SPIN] == "" \
33	||  [auto_execok $SPIN] == 0} {
34		puts "No executable $SPIN found..."
35		puts "iSpin requires Spin Version 6.0 or later"
36		exit 0
37	} else {
38		catch { set fd [open "|$SPIN -V" r] } errmsg
39		if {$fd == -1} {
40			puts "$errmsg"
41			exit 0
42		} else {
43			set version "Spin Version unknown"
44			if {[gets $fd line] > -1} {
45				set version "$line"
46			}
47			catch "close $fd"
48		}
49		if {[string first "Spin Version "  $version] < 0 \
50		||  [string first "Spin Version 5" $version] >= 0 \
51		||  [string first "Spin Version 4" $version] >= 0 \
52		||  [string first "Spin Version 3" $version] >= 0 } {
53			puts "iSpin requires Spin Version 6.0 or later"
54			puts "You have: $version"
55			exit 0
56	}	}
57
58	if {[file isfile $CC] == 0} {	;# symbolic link
59		if {[auto_execok $CC_alt1] != ""} {
60			set CC $CC_alt1
61		} elseif {[auto_execok $CC_alt2] != ""} {
62			set CC $CC_alt2
63	}	}
64
65	if [info exists tcl_platform] {
66		set sys $tcl_platform(platform)
67		if {[string match windows $sys]} {
68			set Unix 0	;# Windows
69	}	}
70
71### Some other configurable items
72	set ScrollBarSize	10
73
74### Colors
75	set MBG azure     ;# menu
76	set MFG black
77
78	set XBB ivory     ;# MSC canvas color
79	set XBG black     ;# MSC rectangle border
80	set XFG	gold      ;# MSC rectangles
81	set XTX black     ;# MSC text
82	set XAR blue      ;# MSC arrows
83	set XPR gray      ;# MSC process line color
84
85	set TBG	azure	  ;#WhiteSmoke	;# text window
86	set TFG	black
87
88	set CBG black     ;# command window
89	set CFG azure     ;# gold
90
91	set NBG	darkblue  ;# main tabs
92	set NFG gold
93
94	set SFG	red       ;# text selections - standout from TBG
95
96	set LTLbg darkblue
97	set LTL_Panel	0 ;# mostly overtaken by extensions in 6.0
98	set V_Panel_1	0 ;# Advanced verification options 1: Error trapping
99	set V_Panel_3	0 ;# ditto 3: Default Parameters
100
101### Fonts
102	set HV0 "helvetica 10"
103	set HV1 "helvetica 11"
104
105### end of configurable items ##########################################
106##                                                                    ##
107## The first part of this code is based on the BWidget-1.9.2 package  ##
108## To skip ahead to where the iSpin specific code starts,             ##
109## search for "iSpin GUI code" which starts about half-way down       ##
110##                                                                    ##
111########################################################################
112
113#######
114## The BWidget Toolkit comes with the following
115## license text that is reproduced here.
116#######
117## BWidget ToolKit
118## Copyright (c) 1998-1999 UNIFIX.
119## Copyright (c) 2001-2002 ActiveState Corp.
120##
121## The following terms apply to all files associated with the software
122## unless explicitly disclaimed in individual files.
123##
124## The authors hereby grant permission to use, copy, modify, distribute,
125## and license this software and its documentation for any purpose, provided
126## that existing copyright notices are retained in all copies and that this
127## notice is included verbatim in any distributions. No written agreement,
128## license, or royalty fee is required for any of the authorized uses.
129## Modifications to this software may be copyrighted by their authors
130## and need not follow the licensing terms described here, provided that
131## the new terms are clearly indicated on the first page of each file where
132## they apply.
133##
134## IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
135## FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
136## ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
137## DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
138## POSSIBILITY OF SUCH DAMAGE.
139##
140## THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
141## INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
142## FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
143## IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
144## NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
145## MODIFICATIONS.
146##
147## GOVERNMENT USE: If you are acquiring this software on behalf of the
148## U.S. government, the Government shall have only "Restricted Rights"
149## in the software and related documentation as defined in the Federal
150## Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
151## are acquiring the software on behalf of the Department of Defense, the
152## software shall be classified as "Commercial Computer Software" and the
153## Government shall have only "Restricted Rights" as defined in Clause
154## 252.227-7013 (c) (1) of DFARs.  Notwithstanding the foregoing, the
155## authors grant the U.S. Government and others acting in its behalf
156## permission to use and distribute the software in accordance with the
157## terms specified in this license.
158#######
159
160namespace eval Widget {}
161
162proc Widget::_opt_defaults {{prio widgetDefault}} {
163    if {$::tcl_version >= 8.4} {
164	set plat [tk windowingsystem]
165    } else {
166	set plat $::tcl_platform(platform)
167    }
168    switch -exact $plat {
169	"aqua" {
170	}
171	"win32" -
172	"windows" {
173	    option add *ListBox.background	SystemWindow $prio
174	    option add *Dialog.padY		0 $prio
175	    option add *Dialog.anchor		e $prio
176	}
177	"x11" -
178	default {
179	    option add *Scrollbar.width		12 $prio
180	    option add *Scrollbar.borderWidth	1  $prio
181	    option add *Dialog.separator	1  $prio
182	    option add *MainFrame.relief	raised $prio
183	    option add *MainFrame.separator	none   $prio
184	}
185    }
186}
187
188Widget::_opt_defaults
189
190bind Entry <<TraverseIn>> { %W selection range 0 end; %W icursor end }
191bind all   <Key-Tab>      { Widget::traverseTo [Widget::focusNext %W] }
192bind all   <<PrevWindow>> { Widget::traverseTo [Widget::focusPrev %W] }
193
194# ----------------------------------------------------------------------------
195#  widget.tcl -- part of Unifix BWidget Toolkit
196# ----------------------------------------------------------------------------
197
198# Uses newer string operations
199package require Tcl 8.1.1
200
201namespace eval Widget {
202    variable _optiontype
203    variable _class
204    variable _tk_widget
205
206    # This controls whether we try to use themed widgets from Tile
207    variable _theme 0
208
209    variable _aqua [expr {($::tcl_version >= 8.4) &&
210			  [string equal [tk windowingsystem] "aqua"]}]
211
212    array set _optiontype {
213        TkResource Widget::_test_tkresource
214        BwResource Widget::_test_bwresource
215        Enum       Widget::_test_enum
216        Int        Widget::_test_int
217        Boolean    Widget::_test_boolean
218        String     Widget::_test_string
219        Flag       Widget::_test_flag
220        Synonym    Widget::_test_synonym
221        Color      Widget::_test_color
222        Padding    Widget::_test_padding
223    }
224
225    proc use {} {}
226}
227
228proc Widget::tkinclude { class tkwidget subpath args } {
229    foreach {cmd lopt} $args {
230        switch -- $cmd {
231            remove {
232                foreach option $lopt {
233                    set remove($option) 1
234                }
235            }
236            include {
237                foreach option $lopt {
238                    set include($option) 1
239                }
240            }
241            prefix {
242                set prefix [lindex $lopt 0]
243                foreach option [lrange $lopt 1 end] {
244                    set rename($option) "-$prefix[string range $option 1 end]"
245                }
246            }
247            rename     -
248            readonly   -
249            initialize {
250                array set $cmd $lopt
251            }
252            default {
253                return -code error "invalid argument \"$cmd\""
254            }
255        }
256    }
257
258    namespace eval $class {}
259    upvar 0 ${class}::opt classopt
260    upvar 0 ${class}::map classmap
261    upvar 0 ${class}::map$subpath submap
262    upvar 0 ${class}::optionExports exports
263
264    set foo [$tkwidget ".ericFoo###"]
265    # create resources informations from tk widget resources
266    foreach optdesc [_get_tkwidget_options $tkwidget] {
267        set option [lindex $optdesc 0]
268        if { (![info exists include] || [info exists include($option)]) &&
269             ![info exists remove($option)] } {
270            if { [llength $optdesc] == 3 } {
271                # option is a synonym
272                set syn [lindex $optdesc 1]
273                if { ![info exists remove($syn)] } {
274                    # original option is not removed
275                    if { [info exists rename($syn)] } {
276                        set classopt($option) [list Synonym $rename($syn)]
277                    } else {
278                        set classopt($option) [list Synonym $syn]
279                    }
280                }
281            } else {
282                if { [info exists rename($option)] } {
283                    set realopt $option
284                    set option  $rename($option)
285                } else {
286                    set realopt $option
287                }
288                if { [info exists initialize($option)] } {
289                    set value $initialize($option)
290                } else {
291                    set value [lindex $optdesc 1]
292                }
293                if { [info exists readonly($option)] } {
294                    set ro $readonly($option)
295                } else {
296                    set ro 0
297                }
298                set classopt($option) \
299			[list TkResource $value $ro [list $tkwidget $realopt]]
300
301		# Add an option database entry for this option
302		set optionDbName ".[lindex [_configure_option $realopt ""] 0]"
303		if { ![string equal $subpath ":cmd"] } {
304		    set optionDbName "$subpath$optionDbName"
305		}
306		option add *${class}$optionDbName $value widgetDefault
307		lappend exports($option) "$optionDbName"
308
309		# Store the forward and backward mappings for this
310		# option <-> realoption pair
311                lappend classmap($option) $subpath "" $realopt
312		set submap($realopt) $option
313            }
314        }
315    }
316    ::destroy $foo
317}
318
319proc Widget::bwinclude { class subclass subpath args } {
320    foreach {cmd lopt} $args {
321        switch -- $cmd {
322            remove {
323                foreach option $lopt {
324                    set remove($option) 1
325                }
326            }
327            include {
328                foreach option $lopt {
329                    set include($option) 1
330                }
331            }
332            prefix {
333                set prefix [lindex $lopt 0]
334                foreach option [lrange $lopt 1 end] {
335                    set rename($option) "-$prefix[string range $option 1 end]"
336                }
337            }
338            rename     -
339            readonly   -
340            initialize {
341                array set $cmd $lopt
342            }
343            default {
344                return -code error "invalid argument \"$cmd\""
345            }
346        }
347    }
348
349    namespace eval $class {}
350    upvar 0 ${class}::opt classopt
351    upvar 0 ${class}::map classmap
352    upvar 0 ${class}::map$subpath submap
353    upvar 0 ${class}::optionExports exports
354    upvar 0 ${subclass}::opt subclassopt
355    upvar 0 ${subclass}::optionExports subexports
356
357    # create resources informations from BWidget resources
358    foreach {option optdesc} [array get subclassopt] {
359	set subOption $option
360        if { (![info exists include] || [info exists include($option)]) &&
361             ![info exists remove($option)] } {
362            set type [lindex $optdesc 0]
363            if { [string equal $type "Synonym"] } {
364                # option is a synonym
365                set syn [lindex $optdesc 1]
366                if { ![info exists remove($syn)] } {
367                    if { [info exists rename($syn)] } {
368                        set classopt($option) [list Synonym $rename($syn)]
369                    } else {
370                        set classopt($option) [list Synonym $syn]
371                    }
372                }
373            } else {
374                if { [info exists rename($option)] } {
375                    set realopt $option
376                    set option  $rename($option)
377                } else {
378                    set realopt $option
379                }
380                if { [info exists initialize($option)] } {
381                    set value $initialize($option)
382                } else {
383                    set value [lindex $optdesc 1]
384                }
385                if { [info exists readonly($option)] } {
386                    set ro $readonly($option)
387                } else {
388                    set ro [lindex $optdesc 2]
389                }
390                set classopt($option) \
391			[list $type $value $ro [lindex $optdesc 3]]
392
393		# Add an option database entry for this option
394		foreach optionDbName $subexports($subOption) {
395		    if { ![string equal $subpath ":cmd"] } {
396			set optionDbName "$subpath$optionDbName"
397		    }
398		    # Only add the option db entry if we are overriding the
399		    # normal widget default
400		    if { [info exists initialize($option)] } {
401			option add *${class}$optionDbName $value \
402				widgetDefault
403		    }
404		    lappend exports($option) "$optionDbName"
405		}
406
407		# Store the forward and backward mappings for this
408		# option <-> realoption pair
409                lappend classmap($option) $subpath $subclass $realopt
410		set submap($realopt) $option
411            }
412        }
413    }
414}
415
416proc Widget::declare { class optlist } {
417    variable _optiontype
418
419    namespace eval $class {}
420    upvar 0 ${class}::opt classopt
421    upvar 0 ${class}::optionExports exports
422    upvar 0 ${class}::optionClass optionClass
423
424    foreach optdesc $optlist {
425        set option  [lindex $optdesc 0]
426        set optdesc [lrange $optdesc 1 end]
427        set type    [lindex $optdesc 0]
428
429        if { ![info exists _optiontype($type)] } {
430            # invalid resource type
431            return -code error "invalid option type \"$type\""
432        }
433
434        if { [string equal $type "Synonym"] } {
435            # test existence of synonym option
436            set syn [lindex $optdesc 1]
437            if { ![info exists classopt($syn)] } {
438                return -code error "unknow option \"$syn\" for Synonym \"$option\""
439            }
440            set classopt($option) [list Synonym $syn]
441            continue
442        }
443
444        # all other resource may have default value, readonly flag and
445        # optional arg depending on type
446        set value [lindex $optdesc 1]
447        set ro    [lindex $optdesc 2]
448        set arg   [lindex $optdesc 3]
449
450        if { [string equal $type "BwResource"] } {
451            # We don't keep BwResource. We simplify to type of sub BWidget
452            set subclass    [lindex $arg 0]
453            set realopt     [lindex $arg 1]
454            if { ![string length $realopt] } {
455                set realopt $option
456            }
457
458            upvar 0 ${subclass}::opt subclassopt
459            if { ![info exists subclassopt($realopt)] } {
460                return -code error "unknow option \"$realopt\""
461            }
462            set suboptdesc $subclassopt($realopt)
463            if { $value == "" } {
464                # We initialize default value
465                set value [lindex $suboptdesc 1]
466            }
467            set type [lindex $suboptdesc 0]
468            set ro   [lindex $suboptdesc 2]
469            set arg  [lindex $suboptdesc 3]
470	    set optionDbName ".[lindex [_configure_option $option ""] 0]"
471	    option add *${class}${optionDbName} $value widgetDefault
472	    set exports($option) $optionDbName
473            set classopt($option) [list $type $value $ro $arg]
474            continue
475        }
476
477        # retreive default value for TkResource
478        if { [string equal $type "TkResource"] } {
479            set tkwidget [lindex $arg 0]
480	    set foo [$tkwidget ".ericFoo##"]
481            set realopt  [lindex $arg 1]
482            if { ![string length $realopt] } {
483                set realopt $option
484            }
485            set tkoptions [_get_tkwidget_options $tkwidget]
486            if { ![string length $value] } {
487                # We initialize default value
488		set ind [lsearch $tkoptions [list $realopt *]]
489                set value [lindex [lindex $tkoptions $ind] end]
490            }
491	    set optionDbName ".[lindex [_configure_option $option ""] 0]"
492	    option add *${class}${optionDbName} $value widgetDefault
493	    set exports($option) $optionDbName
494            set classopt($option) [list TkResource $value $ro \
495		    [list $tkwidget $realopt]]
496	    set optionClass($option) [lindex [$foo configure $realopt] 1]
497	    ::destroy $foo
498            continue
499        }
500
501	set optionDbName ".[lindex [_configure_option $option ""] 0]"
502	option add *${class}${optionDbName} $value widgetDefault
503	set exports($option) $optionDbName
504        # for any other resource type, we keep original optdesc
505        set classopt($option) [list $type $value $ro $arg]
506    }
507}
508
509proc Widget::define { class filename args } {
510    variable ::BWidget::use
511    set use($class)      $args
512    set use($class,file) $filename
513    lappend use(classes) $class
514
515    if {[set x [lsearch -exact $args "-classonly"]] > -1} {
516	set args [lreplace $args $x $x]
517    } else {
518	interp alias {} ::${class} {} ${class}::create
519	proc ::${class}::use {} {}
520
521	bind $class <Destroy> [list Widget::destroy %W]
522    }
523
524    foreach class $args { ${class}::use }
525}
526
527proc Widget::create { class path {rename 1} } {
528    if {$rename} { rename $path ::$path:cmd }
529    proc ::$path { cmd args } \
530    	[subst {return \[eval \[linsert \$args 0 ${class}::\$cmd [list $path]\]\]}]
531    return $path
532}
533
534proc Widget::addmap { class subclass subpath options } {
535    upvar 0 ${class}::opt classopt
536    upvar 0 ${class}::optionExports exports
537    upvar 0 ${class}::optionClass optionClass
538    upvar 0 ${class}::map classmap
539    upvar 0 ${class}::map$subpath submap
540
541    foreach {option realopt} $options {
542        if { ![string length $realopt] } {
543            set realopt $option
544        }
545	set val [lindex $classopt($option) 1]
546	set optDb ".[lindex [_configure_option $realopt ""] 0]"
547	if { ![string equal $subpath ":cmd"] } {
548	    set optDb "$subpath$optDb"
549	}
550	option add *${class}${optDb} $val widgetDefault
551	lappend exports($option) $optDb
552	# Store the forward and backward mappings for this
553	# option <-> realoption pair
554        lappend classmap($option) $subpath $subclass $realopt
555	set submap($realopt) $option
556    }
557}
558
559proc Widget::syncoptions { class subclass subpath options } {
560    upvar 0 ${class}::sync classync
561
562    foreach {option realopt} $options {
563        if { ![string length $realopt] } {
564            set realopt $option
565        }
566        set classync($option) [list $subpath $subclass $realopt]
567    }
568}
569
570proc Widget::init { class path options } {
571    variable _inuse
572    variable _class
573    variable _optiontype
574
575    upvar 0 ${class}::opt classopt
576    upvar 0 ${class}::$path:opt  pathopt
577    upvar 0 ${class}::$path:mod  pathmod
578    upvar 0 ${class}::map classmap
579    upvar 0 ${class}::$path:init pathinit
580
581    if { [info exists pathopt] } {
582	unset pathopt
583    }
584    if { [info exists pathmod] } {
585	unset pathmod
586    }
587
588    set fpath $path
589    set rdbclass [string map [list :: ""] $class]
590    if { ![winfo exists $path] } {
591	set fpath ".#BWidget.#Class#$class"
592	# encapsulation frame to not pollute '.' childspace
593	if {![winfo exists ".#BWidget"]} { frame ".#BWidget" }
594	if { ![winfo exists $fpath] } {
595	    frame $fpath -class $rdbclass
596	}
597    }
598    foreach {option optdesc} [array get classopt] {
599        set pathmod($option) 0
600	if { [info exists classmap($option)] } {
601	    continue
602	}
603        set type [lindex $optdesc 0]
604        if { [string equal $type "Synonym"] } {
605	    continue
606        }
607        if { [string equal $type "TkResource"] } {
608            set alt [lindex [lindex $optdesc 3] 1]
609        } else {
610            set alt ""
611        }
612        set optdb [lindex [_configure_option $option $alt] 0]
613        set def   [option get $fpath $optdb $rdbclass]
614        if { [string length $def] } {
615            set pathopt($option) $def
616        } else {
617            set pathopt($option) [lindex $optdesc 1]
618        }
619    }
620
621    if {![info exists _inuse($class)]} { set _inuse($class) 0 }
622    incr _inuse($class)
623
624    set _class($path) $class
625    foreach {option value} $options {
626        if { ![info exists classopt($option)] } {
627            unset pathopt
628            unset pathmod
629            return -code error "unknown option \"$option\""
630        }
631        set optdesc $classopt($option)
632        set type    [lindex $optdesc 0]
633        if { [string equal $type "Synonym"] } {
634            set option  [lindex $optdesc 1]
635            set optdesc $classopt($option)
636            set type    [lindex $optdesc 0]
637        }
638        # this may fail if a wrong enum element was used
639        if {[catch {
640             $_optiontype($type) $option $value [lindex $optdesc 3]
641        } msg]} {
642            if {[info exists pathopt]} {
643                unset pathopt
644            }
645            unset pathmod
646            return -code error $msg
647        }
648        set pathopt($option) $msg
649	set pathinit($option) $pathopt($option)
650    }
651}
652
653proc Widget::parseArgs {class options} {
654    variable _optiontype
655    upvar 0 ${class}::opt classopt
656    upvar 0 ${class}::map classmap
657
658    foreach {option val} $options {
659	if { ![info exists classopt($option)] } {
660	    error "unknown option \"$option\""
661	}
662        set optdesc $classopt($option)
663        set type    [lindex $optdesc 0]
664        if { [string equal $type "Synonym"] } {
665            set option  [lindex $optdesc 1]
666            set optdesc $classopt($option)
667            set type    [lindex $optdesc 0]
668        }
669	if { [string equal $type "TkResource"] } {
670	    # Make sure that the widget used for this TkResource exists
671	    Widget::_get_tkwidget_options [lindex [lindex $optdesc 3] 0]
672	}
673	set val [$_optiontype($type) $option $val [lindex $optdesc 3]]
674
675	if { [info exists classmap($option)] } {
676	    foreach {subpath subclass realopt} $classmap($option) {
677		lappend maps($subpath) $realopt $val
678	    }
679	} else {
680	    lappend maps($class) $option $val
681	}
682    }
683    return [array get maps]
684}
685
686proc Widget::initFromODB {class path options} {
687    variable _inuse
688    variable _class
689
690    upvar 0 ${class}::$path:opt  pathopt
691    upvar 0 ${class}::$path:mod  pathmod
692    upvar 0 ${class}::map classmap
693
694    if { [info exists pathopt] } {
695	unset pathopt
696    }
697    if { [info exists pathmod] } {
698	unset pathmod
699    }
700
701    set fpath [_get_window $class $path]
702    set rdbclass [string map [list :: ""] $class]
703    if { ![winfo exists $path] } {
704	set fpath ".#BWidget.#Class#$class"
705	# encapsulation frame to not pollute '.' childspace
706	if {![winfo exists ".#BWidget"]} { frame ".#BWidget" }
707	if { ![winfo exists $fpath] } {
708	    frame $fpath -class $rdbclass
709	}
710    }
711
712    foreach {option optdesc} [array get ${class}::opt] {
713        set pathmod($option) 0
714	if { [info exists classmap($option)] } {
715	    continue
716	}
717        set type [lindex $optdesc 0]
718        if { [string equal $type "Synonym"] } {
719	    continue
720        }
721	if { [string equal $type "TkResource"] } {
722            set alt [lindex [lindex $optdesc 3] 1]
723        } else {
724            set alt ""
725        }
726        set optdb [lindex [_configure_option $option $alt] 0]
727        set def   [option get $fpath $optdb $rdbclass]
728        if { [string length $def] } {
729            set pathopt($option) $def
730        } else {
731            set pathopt($option) [lindex $optdesc 1]
732        }
733    }
734
735    if {![info exists _inuse($class)]} { set _inuse($class) 0 }
736    incr _inuse($class)
737
738    set _class($path) $class
739    array set pathopt $options
740}
741
742proc Widget::destroy { path } {
743    variable _class
744    variable _inuse
745
746    if {![info exists _class($path)]} { return }
747
748    set class $_class($path)
749    upvar 0 ${class}::$path:opt pathopt
750    upvar 0 ${class}::$path:mod pathmod
751    upvar 0 ${class}::$path:init pathinit
752
753    if {[info exists _inuse($class)]} { incr _inuse($class) -1 }
754
755    if {[info exists pathopt]} {
756        unset pathopt
757    }
758    if {[info exists pathmod]} {
759        unset pathmod
760    }
761    if {[info exists pathinit]} {
762        unset pathinit
763    }
764
765    if {![string equal [info commands $path] ""]} { rename $path "" }
766
767    ## Unset any variables used in this widget.
768    foreach var [info vars ::${class}::$path:*] { unset $var }
769
770    unset _class($path)
771}
772
773proc Widget::configure { path options } {
774    set len [llength $options]
775    if { $len <= 1 } {
776        return [_get_configure $path $options]
777    } elseif { $len % 2 == 1 } {
778        return -code error "incorrect number of arguments"
779    }
780
781    variable _class
782    variable _optiontype
783
784    set class $_class($path)
785    upvar 0 ${class}::opt  classopt
786    upvar 0 ${class}::map  classmap
787    upvar 0 ${class}::$path:opt pathopt
788    upvar 0 ${class}::$path:mod pathmod
789
790    set window [_get_window $class $path]
791    foreach {option value} $options {
792        if { ![info exists classopt($option)] } {
793            return -code error "unknown option \"$option\""
794        }
795        set optdesc $classopt($option)
796        set type    [lindex $optdesc 0]
797        if { [string equal $type "Synonym"] } {
798            set option  [lindex $optdesc 1]
799            set optdesc $classopt($option)
800            set type    [lindex $optdesc 0]
801        }
802        if { ![lindex $optdesc 2] } {
803            set newval [$_optiontype($type) $option $value [lindex $optdesc 3]]
804            if { [info exists classmap($option)] } {
805		set window [_get_window $class $window]
806                foreach {subpath subclass realopt} $classmap($option) {
807                    if { [string length $subclass] && ! [string equal $subclass ":cmd"] } {
808                        if { [string equal $subpath ":cmd"] } {
809                            set subpath ""
810                        }
811                        set curval [${subclass}::cget $window$subpath $realopt]
812                        ${subclass}::configure $window$subpath $realopt $newval
813                    } else {
814                        set curval [$window$subpath cget $realopt]
815                        $window$subpath configure $realopt $newval
816                    }
817                }
818            } else {
819		set curval $pathopt($option)
820		set pathopt($option) $newval
821	    }
822	    set pathmod($option) [expr {![string equal $newval $curval]}]
823        }
824    }
825
826    return {}
827}
828
829proc Widget::cget { path option } {
830    variable _class
831    if { ![info exists _class($path)] } {
832        return -code error "unknown widget $path"
833    }
834
835    set class $_class($path)
836    if { ![info exists ${class}::opt($option)] } {
837        return -code error "unknown option \"$option\""
838    }
839
840    set optdesc [set ${class}::opt($option)]
841    set type    [lindex $optdesc 0]
842    if {[string equal $type "Synonym"]} {
843        set option [lindex $optdesc 1]
844    }
845
846    if { [info exists ${class}::map($option)] } {
847	foreach {subpath subclass realopt} [set ${class}::map($option)] {break}
848	set path "[_get_window $class $path]$subpath"
849	return [$path cget $realopt]
850    }
851    upvar 0 ${class}::$path:opt pathopt
852    set pathopt($option)
853}
854
855proc Widget::subcget { path subwidget } {
856    variable _class
857    set class $_class($path)
858    upvar 0 ${class}::$path:opt pathopt
859    upvar 0 ${class}::map$subwidget submap
860    upvar 0 ${class}::$path:init pathinit
861
862    set result {}
863    foreach realopt [array names submap] {
864	if { [info exists pathinit($submap($realopt))] } {
865	    lappend result $realopt $pathopt($submap($realopt))
866	}
867    }
868    return $result
869}
870
871proc Widget::hasChanged { path option pvalue } {
872    variable _class
873    upvar $pvalue value
874    set class $_class($path)
875    upvar 0 ${class}::$path:mod pathmod
876
877    set value   [Widget::cget $path $option]
878    set result  $pathmod($option)
879    set pathmod($option) 0
880
881    return $result
882}
883
884proc Widget::hasChangedX { path option args } {
885    variable _class
886    set class $_class($path)
887    upvar 0 ${class}::$path:mod pathmod
888
889    set result  $pathmod($option)
890    set pathmod($option) 0
891    foreach option $args {
892	lappend result $pathmod($option)
893	set pathmod($option) 0
894    }
895
896    set result
897}
898
899proc Widget::setoption { path option value } {
900    Widget::configure $path [list $option $value]
901}
902
903proc Widget::getoption { path option } {
904    return [Widget::cget $path $option]
905}
906
907proc Widget::getMegawidgetOption {path option} {
908    variable _class
909    set class $_class($path)
910    upvar 0 ${class}::${path}:opt pathopt
911    set pathopt($option)
912}
913
914proc Widget::setMegawidgetOption {path option value} {
915    variable _class
916    set class $_class($path)
917    upvar 0 ${class}::${path}:opt pathopt
918    set pathopt($option) $value
919}
920
921proc Widget::_get_window { class path } {
922    set idx [string last "#" $path]
923    if { $idx != -1 && [string equal [string range $path [expr {$idx+1}] end] $class] } {
924        return [string range $path 0 [expr {$idx-1}]]
925    } else {
926        return $path
927    }
928}
929
930proc Widget::_get_configure { path options } {
931    variable _class
932
933    set class $_class($path)
934    upvar 0 ${class}::opt classopt
935    upvar 0 ${class}::map classmap
936    upvar 0 ${class}::$path:opt pathopt
937    upvar 0 ${class}::$path:mod pathmod
938
939    set len [llength $options]
940    if { !$len } {
941        set result {}
942        foreach option [lsort [array names classopt]] {
943            set optdesc $classopt($option)
944            set type    [lindex $optdesc 0]
945            if { [string equal $type "Synonym"] } {
946                set syn     $option
947                set option  [lindex $optdesc 1]
948                set optdesc $classopt($option)
949                set type    [lindex $optdesc 0]
950            } else {
951                set syn ""
952            }
953            if { [string equal $type "TkResource"] } {
954                set alt [lindex [lindex $optdesc 3] 1]
955            } else {
956                set alt ""
957            }
958            set res [_configure_option $option $alt]
959            if { $syn == "" } {
960                lappend result [concat $option $res [list [lindex $optdesc 1]] [list [cget $path $option]]]
961            } else {
962                lappend result [list $syn [lindex $res 0]]
963            }
964        }
965        return $result
966    } elseif { $len == 1 } {
967        set option  [lindex $options 0]
968        if { ![info exists classopt($option)] } {
969            return -code error "unknown option \"$option\""
970        }
971        set optdesc $classopt($option)
972        set type    [lindex $optdesc 0]
973        if { [string equal $type "Synonym"] } {
974            set option  [lindex $optdesc 1]
975            set optdesc $classopt($option)
976            set type    [lindex $optdesc 0]
977        }
978        if { [string equal $type "TkResource"] } {
979            set alt [lindex [lindex $optdesc 3] 1]
980        } else {
981            set alt ""
982        }
983        set res [_configure_option $option $alt]
984        return [concat $option $res [list [lindex $optdesc 1]] [list [cget $path $option]]]
985    }
986}
987
988proc Widget::_configure_option { option altopt } {
989    variable _optiondb
990    variable _optionclass
991
992    if { [info exists _optiondb($option)] } {
993        set optdb $_optiondb($option)
994    } else {
995        set optdb [string range $option 1 end]
996    }
997    if { [info exists _optionclass($option)] } {
998        set optclass $_optionclass($option)
999    } elseif { [string length $altopt] } {
1000        if { [info exists _optionclass($altopt)] } {
1001            set optclass $_optionclass($altopt)
1002        } else {
1003            set optclass [string range $altopt 1 end]
1004        }
1005    } else {
1006        set optclass [string range $option 1 end]
1007    }
1008    return [list $optdb $optclass]
1009}
1010
1011proc Widget::_get_tkwidget_options { tkwidget } {
1012    variable _tk_widget
1013    variable _optiondb
1014    variable _optionclass
1015
1016    set widget ".#BWidget.#$tkwidget"
1017    # encapsulation frame to not pollute '.' childspace
1018    if {![winfo exists ".#BWidget"]} { frame ".#BWidget" }
1019    if { ![winfo exists $widget] || ![info exists _tk_widget($tkwidget)] } {
1020	set widget [$tkwidget $widget]
1021	# JDC: Withdraw toplevels, otherwise visible
1022	if {[string equal $tkwidget "toplevel"]} {
1023	    wm withdraw $widget
1024	}
1025	set config [$widget configure]
1026	foreach optlist $config {
1027	    set opt [lindex $optlist 0]
1028	    if { [llength $optlist] == 2 } {
1029		set refsyn [lindex $optlist 1]
1030		# search for class
1031		set idx [lsearch $config [list * $refsyn *]]
1032		if { $idx == -1 } {
1033		    if { [string index $refsyn 0] == "-" } {
1034			# search for option (tk8.1b1 bug)
1035			set idx [lsearch $config [list $refsyn * *]]
1036		    } else {
1037			# last resort
1038			set idx [lsearch $config [list -[string tolower $refsyn] * *]]
1039		    }
1040		    if { $idx == -1 } {
1041			# fed up with "can't read classopt()"
1042			return -code error "can't find option of synonym $opt"
1043		    }
1044		}
1045		set syn [lindex [lindex $config $idx] 0]
1046		# JDC: used 4 (was 3) to get def from optiondb
1047		set def [lindex [lindex $config $idx] 4]
1048		lappend _tk_widget($tkwidget) [list $opt $syn $def]
1049	    } else {
1050		# JDC: used 4 (was 3) to get def from optiondb
1051		set def [lindex $optlist 4]
1052		lappend _tk_widget($tkwidget) [list $opt $def]
1053		set _optiondb($opt)    [lindex $optlist 1]
1054		set _optionclass($opt) [lindex $optlist 2]
1055	    }
1056	}
1057    }
1058    return $_tk_widget($tkwidget)
1059}
1060
1061proc Widget::_test_tkresource { option value arg } {
1062    foreach {tkwidget realopt} $arg break
1063    set path     ".#BWidget.#$tkwidget"
1064    set old      [$path cget $realopt]
1065    $path configure $realopt $value
1066    set res      [$path cget $realopt]
1067    $path configure $realopt $old
1068
1069    return $res
1070}
1071
1072proc Widget::_test_bwresource { option value arg } {
1073    return -code error "bad option type BwResource in widget"
1074}
1075
1076proc Widget::_test_synonym { option value arg } {
1077    return -code error "bad option type Synonym in widget"
1078}
1079
1080proc Widget::_test_color { option value arg } {
1081    if {[catch {winfo rgb . $value} color]} {
1082        return -code error "bad $option value \"$value\": must be a colorname \
1083		or #RRGGBB triplet"
1084    }
1085
1086    return $value
1087}
1088
1089proc Widget::_test_string { option value arg } {
1090    set value
1091}
1092
1093proc Widget::_test_flag { option value arg } {
1094    set len [string length $value]
1095    set res ""
1096    for {set i 0} {$i < $len} {incr i} {
1097        set c [string index $value $i]
1098        if { [string first $c $arg] == -1 } {
1099            return -code error "bad [string range $option 1 end] value \"$value\": characters must be in \"$arg\""
1100        }
1101        if { [string first $c $res] == -1 } {
1102            append res $c
1103        }
1104    }
1105    return $res
1106}
1107
1108proc Widget::_test_enum { option value arg } {
1109    if { [lsearch $arg $value] == -1 } {
1110        set last [lindex   $arg end]
1111        set sub  [lreplace $arg end end]
1112        if { [llength $sub] } {
1113            set str "[join $sub ", "] or $last"
1114        } else {
1115            set str $last
1116        }
1117        return -code error "bad [string range $option 1 end] value \"$value\": must be $str"
1118    }
1119    return $value
1120}
1121
1122proc Widget::_test_int { option value arg } {
1123    if { ![string is int -strict $value] || \
1124	    ([string length $arg] && \
1125	    ![expr [string map [list %d $value] $arg]]) } {
1126		    return -code error "bad $option value\
1127			    \"$value\": must be integer ($arg)"
1128    }
1129    return $value
1130}
1131
1132proc Widget::_test_boolean { option value arg } {
1133    if { ![string is boolean -strict $value] } {
1134        return -code error "bad $option value \"$value\": must be boolean"
1135    }
1136
1137    # Get the canonical form of the boolean value (1 for true, 0 for false)
1138    return [string is true $value]
1139}
1140
1141proc Widget::_test_padding { option values arg } {
1142    set len [llength $values]
1143    if {$len < 1 || $len > 2} {
1144        return -code error "bad pad value \"$values\":\
1145                        must be positive screen distance"
1146    }
1147
1148    foreach value $values {
1149        if { ![string is int -strict $value] || \
1150            ([string length $arg] && \
1151            ![expr [string map [list %d $value] $arg]]) } {
1152                return -code error "bad pad value \"$value\":\
1153                                must be positive screen distance ($arg)"
1154        }
1155    }
1156    return $values
1157}
1158
1159proc Widget::_get_padding { path option {index 0} } {
1160    set pad [Widget::cget $path $option]
1161    set val [lindex $pad $index]
1162    if {$val == ""} { set val [lindex $pad 0] }
1163    return $val
1164}
1165
1166proc Widget::focusNext { w } {
1167    set cur $w
1168    while 1 {
1169	# Descend to just before the first child of the current widget.
1170	set parent $cur
1171	set children [winfo children $cur]
1172	set i -1
1173
1174	# Look for the next sibling that isn't a top-level.
1175	while 1 {
1176	    incr i
1177	    if {$i < [llength $children]} {
1178		set cur [lindex $children $i]
1179		if {[string equal [winfo toplevel $cur] $cur]} {
1180		    continue
1181		} else {
1182		    break
1183		}
1184	    }
1185
1186	    set cur $parent
1187	    if {[string equal [winfo toplevel $cur] $cur]} {
1188		break
1189	    }
1190	    set parent [winfo parent $parent]
1191	    set children [winfo children $parent]
1192	    set i [lsearch -exact $children $cur]
1193	}
1194	if {[string equal $cur $w] || [focusOK $cur]} {
1195	    return $cur
1196	}
1197    }
1198}
1199
1200proc Widget::focusPrev { w } {
1201    set cur $w
1202    set origParent [winfo parent $w]
1203    while 1 {
1204
1205	if {[string equal [winfo toplevel $cur] $cur]}  {
1206	    set parent $cur
1207	    set children [winfo children $cur]
1208	    set i [llength $children]
1209	} else {
1210	    set parent [winfo parent $cur]
1211	    set children [winfo children $parent]
1212	    set i [lsearch -exact $children $cur]
1213	}
1214
1215	while {$i > 0} {
1216	    incr i -1
1217	    set cur [lindex $children $i]
1218	    if {[string equal [winfo toplevel $cur] $cur]} {
1219		continue
1220	    }
1221	    set parent $cur
1222	    set children [winfo children $parent]
1223	    set i [llength $children]
1224	}
1225	set cur $parent
1226	if {[string equal $cur $w]} {
1227	    return $cur
1228	}
1229
1230	if {[string equal $cur $origParent]
1231	    && [info procs ::$origParent] != ""} {
1232	    continue
1233	}
1234	if {[focusOK $cur]} {
1235	    return $cur
1236	}
1237    }
1238}
1239
1240proc Widget::focusOK { w } {
1241    set code [catch {$w cget -takefocus} value]
1242    if { $code == 1 } {
1243        return 0
1244    }
1245    if {($code == 0) && ($value != "")} {
1246	if {$value == 0} {
1247	    return 0
1248	} elseif {$value == 1} {
1249	    return [winfo viewable $w]
1250	} else {
1251	    set value [uplevel \#0 $value $w]
1252            if {$value != ""} {
1253		return $value
1254	    }
1255        }
1256    }
1257    if {![winfo viewable $w]} {
1258	return 0
1259    }
1260    set code [catch {$w cget -state} value]
1261    if {($code == 0) && ($value == "disabled")} {
1262	return 0
1263    }
1264    set code [catch {$w cget -editable} value]
1265    if {($code == 0) && ($value == 0)} {
1266        return 0
1267    }
1268
1269    set top [winfo toplevel $w]
1270    foreach tags [bindtags $w] {
1271        if { ![string equal $tags $top]  &&
1272             ![string equal $tags "all"] &&
1273             [regexp Key [bind $tags]] } {
1274            return 1
1275        }
1276    }
1277    return 0
1278}
1279
1280proc Widget::traverseTo { w } {
1281    set focus [focus]
1282    if {![string equal $focus ""]} {
1283	event generate $focus <<TraverseOut>>
1284    }
1285    focus $w
1286
1287    event generate $w <<TraverseIn>>
1288}
1289
1290proc Widget::getVariable { path varName {newVarName ""} } {
1291    variable _class
1292    set class $_class($path)
1293    if {![string length $newVarName]} { set newVarName $varName }
1294    uplevel 1 [list upvar \#0 ${class}::$path:$varName $newVarName]
1295}
1296
1297proc Widget::options { path args } {
1298    if {[llength $args]} {
1299        foreach option $args {
1300            lappend options [_get_configure $path $option]
1301        }
1302    } else {
1303        set options [_get_configure $path {}]
1304    }
1305
1306    set result [list]
1307    foreach list $options {
1308        if {[llength $list] < 5} { continue }
1309        lappend result [lindex $list 0] [lindex $list end]
1310    }
1311    return $result
1312}
1313
1314proc Widget::exists { path } {
1315    variable _class
1316    return [info exists _class($path)]
1317}
1318# ----------------------------------------------------------------------------
1319#  utils.tcl -- part of Unifix BWidget Toolkit
1320# ----------------------------------------------------------------------------
1321
1322namespace eval BWidget {
1323    variable _top
1324    variable _gstack {}
1325    variable _fstack {}
1326    proc use {} {}
1327}
1328
1329proc BWidget::get3dcolor { path bgcolor } {
1330    foreach val [winfo rgb $path $bgcolor] {
1331        lappend dark [expr {60*$val/100}]
1332        set tmp1 [expr {14*$val/10}]
1333        if { $tmp1 > 65535 } {
1334            set tmp1 65535
1335        }
1336        set tmp2 [expr {(65535+$val)/2}]
1337        lappend light [expr {($tmp1 > $tmp2) ? $tmp1:$tmp2}]
1338    }
1339    return [list [eval format "#%04x%04x%04x" $dark] [eval format "#%04x%04x%04x" $light]]
1340}
1341# ----------------------------------------------------------------------------
1342#  panedw.tcl -- part of Unifix BWidget Toolkit
1343# ----------------------------------------------------------------------------
1344
1345namespace eval PanedWindow {
1346    Widget::define PanedWindow panedw
1347
1348    namespace eval Pane {
1349        Widget::declare PanedWindow::Pane {
1350            {-minsize Int 0 0 "%d >= 0"}
1351            {-weight  Int 1 0 "%d >= 0"}
1352        }
1353    }
1354
1355    Widget::declare PanedWindow {
1356        {-side       Enum       top   1 {top left bottom right}}
1357        {-width      Int        10    1 "%d >=3"}
1358        {-pad        Int        4     1 "%d >= 0"}
1359        {-background TkResource ""    0 frame}
1360        {-bg         Synonym    -background}
1361        {-activator  Enum       ""    1 {line button}}
1362	{-weights    Enum       extra 1 {extra available}}
1363    }
1364
1365    variable _panedw
1366}
1367
1368proc PanedWindow::create { path args } {
1369    variable _panedw
1370
1371    Widget::init PanedWindow $path $args
1372
1373    frame $path -background [Widget::cget $path -background] -class PanedWindow
1374    set _panedw($path,nbpanes) 0
1375    set _panedw($path,weights) ""
1376    set _panedw($path,configuredone) 0
1377
1378    set activator [Widget::getoption $path -activator]
1379    if {[string equal $activator ""]} {
1380        if { $::tcl_platform(platform) != "windows" } {
1381            Widget::setMegawidgetOption $path -activator button
1382        } else {
1383            Widget::setMegawidgetOption $path -activator line
1384        }
1385    }
1386    if {[string equal [Widget::getoption $path -activator] "line"]} {
1387        Widget::setMegawidgetOption $path -width 3
1388    }
1389
1390    bind $path <Configure> [list PanedWindow::_realize $path %w %h]
1391    bind $path <Destroy>   [list PanedWindow::_destroy $path]
1392
1393    return [Widget::create PanedWindow $path]
1394}
1395
1396proc PanedWindow::configure { path args } {
1397    variable _panedw
1398
1399    set res [Widget::configure $path $args]
1400
1401    if { [Widget::hasChanged $path -background bg] && $_panedw($path,nbpanes) > 0 } {
1402        $path:cmd configure -background $bg
1403        $path.f0 configure -background $bg
1404        for {set i 1} {$i < $_panedw($path,nbpanes)} {incr i} {
1405            set frame $path.sash$i
1406            $frame configure -background $bg
1407            $frame.sep configure -background $bg
1408            $frame.but configure -background $bg
1409            $path.f$i configure -background $bg
1410            $path.f$i.frame configure -background $bg
1411        }
1412    }
1413    return $res
1414}
1415
1416proc PanedWindow::cget { path option } {
1417    return [Widget::cget $path $option]
1418}
1419
1420proc PanedWindow::add { path args } {
1421    variable _panedw
1422
1423    set num $_panedw($path,nbpanes)
1424    Widget::init PanedWindow::Pane $path.f$num $args
1425    set bg [Widget::getoption $path -background]
1426
1427    set wbut   [Widget::getoption $path -width]
1428    set pad    [Widget::getoption $path -pad]
1429    set width  [expr {$wbut+2*$pad}]
1430    set side   [Widget::getoption $path -side]
1431    set weight [Widget::getoption $path.f$num -weight]
1432    lappend _panedw($path,weights) $weight
1433
1434    if { $num > 0 } {
1435        set frame [frame $path.sash$num -relief flat -bd 0 \
1436                       -highlightthickness 0 -width $width -height $width -bg $bg]
1437        set sep [frame $frame.sep -bd 5 -relief raised \
1438                     -highlightthickness 0 -bg $bg]
1439        set but [frame $frame.but -bd 1 -relief raised \
1440                     -highlightthickness 0 -bg $bg -width $wbut -height $wbut]
1441	set sepsize 2
1442
1443        set activator [Widget::getoption $path -activator]
1444	if {$activator == "button"} {
1445	    set activator $but
1446	    set placeButton 1
1447	} else {
1448	    set activator $sep
1449	    $sep configure -bd 1
1450	    set placeButton 0
1451	}
1452        if {[string equal $side "top"] || [string equal $side "bottom"]} {
1453            place $sep -relx 0.5 -y 0 -width $sepsize -relheight 1.0 -anchor n
1454	    if { $placeButton } {
1455		if {[string equal $side "top"]} {
1456		    place $but -relx 0.5 -y [expr {6+$wbut/2}] -anchor c
1457		} else {
1458		    place $but -relx 0.5 -rely 1.0 -y [expr {-6-$wbut/2}] \
1459			    -anchor c
1460		}
1461	    }
1462            $activator configure -cursor sb_h_double_arrow
1463            grid $frame -column [expr {2*$num-1}] -row 0 -sticky ns
1464            grid columnconfigure $path [expr {2*$num-1}] -weight 0
1465        } else {
1466            place $sep -x 0 -rely 0.5 -height $sepsize -relwidth 1.0 -anchor w
1467	    if { $placeButton } {
1468		if {[string equal $side "left"]} {
1469		    place $but -rely 0.5 -x [expr {6+$wbut/2}] -anchor c
1470		} else {
1471		    place $but -rely 0.5 -relx 1.0 -x [expr {-6-$wbut/2}] \
1472			    -anchor c
1473		}
1474	    }
1475            $activator configure -cursor sb_v_double_arrow
1476            grid $frame -row [expr {2*$num-1}] -column 0 -sticky ew
1477            grid rowconfigure $path [expr {2*$num-1}] -weight 0
1478        }
1479        bind $activator <ButtonPress-1> \
1480	    [list PanedWindow::_beg_move_sash $path $num %X %Y]
1481    } else {
1482        if { [string equal $side "top"] || \
1483		[string equal $side "bottom"] } {
1484            grid rowconfigure $path 0 -weight 1
1485        } else {
1486            grid columnconfigure $path 0 -weight 1
1487        }
1488    }
1489
1490    set pane [frame $path.f$num -bd 0 -relief flat \
1491	    -highlightthickness 0 -bg $bg]
1492    set user [frame $path.f$num.frame  -bd 0 -relief flat \
1493	    -highlightthickness 0 -bg $bg]
1494    if { [string equal $side "top"] || [string equal $side "bottom"] } {
1495        grid $pane -column [expr {2*$num}] -row 0 -sticky nsew
1496        grid columnconfigure $path [expr {2*$num}] -weight $weight
1497    } else {
1498        grid $pane -row [expr {2*$num}] -column 0 -sticky nsew
1499        grid rowconfigure $path [expr {2*$num}] -weight $weight
1500    }
1501    pack $user -fill both -expand yes
1502    incr _panedw($path,nbpanes)
1503    if {$_panedw($path,configuredone)} {
1504	_realize $path [winfo width $path] [winfo height $path]
1505    }
1506
1507    return $user
1508}
1509
1510proc PanedWindow::getframe { path index } {
1511    if { [winfo exists $path.f$index.frame] } {
1512        return $path.f$index.frame
1513    }
1514}
1515
1516proc PanedWindow::_beg_move_sash { path num x y } {
1517    variable _panedw
1518
1519    set fprev $path.f[expr {$num-1}]
1520    set fnext $path.f$num
1521    set wsash [expr {[Widget::getoption $path -width] + 2*[Widget::getoption $path -pad]}]
1522
1523    $path.sash$num.but configure -relief sunken
1524    set top  [toplevel $path.sash -borderwidth 1 -relief raised]
1525
1526    set minszg [Widget::getoption $fprev -minsize]
1527    set minszd [Widget::getoption $fnext -minsize]
1528    set side   [Widget::getoption $path -side]
1529
1530    if { [string equal $side "top"] || [string equal $side "bottom"] } {
1531        $top configure -cursor sb_h_double_arrow
1532        set h    [winfo height $path]
1533        set yr   [winfo rooty $path.sash$num]
1534        set xmin [expr {$wsash/2+[winfo rootx $fprev]+$minszg}]
1535        set xmax [expr {-$wsash/2-1+[winfo rootx $fnext]+[winfo width $fnext]-$minszd}]
1536        wm overrideredirect $top 1
1537        wm geom $top "2x${h}+$x+$yr"
1538
1539        update idletasks
1540        grab set $top
1541        bind $top <ButtonRelease-1> [list PanedWindow::_end_move_sash $path $top $num $xmin $xmax %X rootx width]
1542        bind $top <Motion>          [list PanedWindow::_move_sash $top $xmin $xmax %X +%%d+$yr]
1543        _move_sash $top $xmin $xmax $x "+%d+$yr"
1544    } else {
1545        $top configure -cursor sb_v_double_arrow
1546        set w    [winfo width $path]
1547        set xr   [winfo rootx $path.sash$num]
1548        set ymin [expr {$wsash/2+[winfo rooty $fprev]+$minszg}]
1549        set ymax [expr {-$wsash/2-1+[winfo rooty $fnext]+[winfo height $fnext]-$minszd}]
1550        wm overrideredirect $top 1
1551        wm geom $top "${w}x2+$xr+$y"
1552
1553        update idletasks
1554        grab set $top
1555        bind $top <ButtonRelease-1> [list PanedWindow::_end_move_sash \
1556		$path $top $num $ymin $ymax %Y rooty height]
1557        bind $top <Motion>          [list PanedWindow::_move_sash \
1558		$top $ymin $ymax %Y +$xr+%%d]
1559        _move_sash $top $ymin $ymax $y "+$xr+%d"
1560    }
1561}
1562
1563proc PanedWindow::_move_sash { top min max v form } {
1564
1565    if { $v < $min } {
1566	set v $min
1567    } elseif { $v > $max } {
1568	set v $max
1569    }
1570    wm geom $top [format $form $v]
1571}
1572
1573proc PanedWindow::_end_move_sash { path top num min max v rootv size } {
1574    variable _panedw
1575
1576    destroy $top
1577    if { $v < $min } {
1578	set v $min
1579    } elseif { $v > $max } {
1580	set v $max
1581    }
1582    set fprev $path.f[expr {$num-1}]
1583    set fnext $path.f$num
1584
1585    $path.sash$num.but configure -relief raised
1586
1587    set wsash [expr {[Widget::getoption $path -width] + 2*[Widget::getoption $path -pad]}]
1588    set dv    [expr {$v-[winfo $rootv $path.sash$num]-$wsash/2}]
1589    set w1    [winfo $size $fprev]
1590    set w2    [winfo $size $fnext]
1591
1592    for {set i 0} {$i < $_panedw($path,nbpanes)} {incr i} {
1593        if { $i == $num-1} {
1594            $fprev configure -$size [expr {[winfo $size $fprev]+$dv}]
1595        } elseif { $i == $num } {
1596            $fnext configure -$size [expr {[winfo $size $fnext]-$dv}]
1597        } else {
1598            $path.f$i configure -$size [winfo $size $path.f$i]
1599        }
1600    }
1601}
1602
1603proc PanedWindow::_realize { path width height } {
1604    variable _panedw
1605
1606    set x    0
1607    set y    0
1608    set hc   [winfo reqheight $path]
1609    set hmax 0
1610    for {set i 0} {$i < $_panedw($path,nbpanes)} {incr i} {
1611        $path.f$i configure \
1612            -width  [winfo reqwidth  $path.f$i.frame] \
1613            -height [winfo reqheight $path.f$i.frame]
1614        place $path.f$i.frame -x 0 -y 0 -relwidth 1 -relheight 1
1615    }
1616
1617    bind $path <Configure> {}
1618
1619    _apply_weights $path
1620    set _panedw($path,configuredone) 1
1621    return
1622}
1623
1624proc PanedWindow::_apply_weights { path } {
1625    variable _panedw
1626
1627    set weights [Widget::getoption $path -weights]
1628    if {[string equal $weights "extra"]} {
1629	return
1630    }
1631
1632    set side   [Widget::getoption $path -side]
1633    if {[string equal $side "top"] || [string equal $side "bottom"] } {
1634	set size width
1635    } else {
1636	set size height
1637    }
1638    set wsash [expr {[Widget::getoption $path -width] + 2*[Widget::getoption $path -pad]}]
1639    set rs [winfo $size $path]
1640    set s [expr {$rs - ($_panedw($path,nbpanes) - 1) * $wsash}]
1641
1642    set tw 0.0
1643    foreach w $_panedw($path,weights) {
1644	set tw [expr {$tw + $w}]
1645    }
1646
1647    for {set i 0} {$i < $_panedw($path,nbpanes)} {incr i} {
1648	set rw [lindex $_panedw($path,weights) $i]
1649	set ps [expr {int($rw / $tw * $s)}]
1650	$path.f$i configure -$size $ps
1651    }
1652    return
1653}
1654
1655proc PanedWindow::_destroy { path } {
1656    variable _panedw
1657
1658    for {set i 0} {$i < $_panedw($path,nbpanes)} {incr i} {
1659        Widget::destroy $path.f$i
1660    }
1661    unset _panedw($path,nbpanes)
1662    Widget::destroy $path
1663}
1664# ------------------------------------------------------------------------------
1665#  arrow.tcl -- part of Unifix BWidget Toolkit
1666# ------------------------------------------------------------------------------
1667
1668namespace eval ArrowButton {
1669    Widget::define ArrowButton arrow
1670
1671    Widget::tkinclude ArrowButton button .c \
1672	    include [list \
1673		-borderwidth -bd \
1674		-relief -highlightbackground \
1675		-highlightcolor -highlightthickness -takefocus]
1676
1677    Widget::declare ArrowButton [list \
1678	    [list -type		Enum button 0 [list arrow button]] \
1679	    [list -dir		Enum top    0 [list top bottom left right]] \
1680	    [list -width	Int	15	0	"%d >= 0"] \
1681	    [list -height	Int	15	0	"%d >= 0"] \
1682	    [list -ipadx	Int	0	0	"%d >= 0"] \
1683	    [list -ipady	Int	0	0	"%d >= 0"] \
1684	    [list -clean	Int	2	0	"%d >= 0 && %d <= 2"] \
1685	    [list -activeforeground	TkResource	""	0 button] \
1686	    [list -activebackground	TkResource	""	0 button] \
1687	    [list -disabledforeground 	TkResource	""	0 button] \
1688	    [list -foreground		TkResource	""	0 button] \
1689	    [list -background		TkResource	""	0 button] \
1690	    [list -state		TkResource	""	0 button] \
1691	    [list -troughcolor		TkResource	""	0 scrollbar] \
1692	    [list -arrowbd	Int	1	0	"%d >= 0 && %d <= 2"] \
1693	    [list -arrowrelief	Enum	raised	0	[list raised sunken]] \
1694	    [list -command		String	""	0] \
1695	    [list -armcommand		String	""	0] \
1696	    [list -disarmcommand	String	""	0] \
1697	    [list -repeatdelay		Int	0	0	"%d >= 0"] \
1698	    [list -repeatinterval	Int	0	0	"%d >= 0"] \
1699	    [list -fg	Synonym	-foreground] \
1700	    [list -bg	Synonym	-background] \
1701	    ]
1702
1703    bind BwArrowButtonC <Enter>           {ArrowButton::_enter %W}
1704    bind BwArrowButtonC <Leave>           {ArrowButton::_leave %W}
1705    bind BwArrowButtonC <ButtonPress-1>   {ArrowButton::_press %W}
1706    bind BwArrowButtonC <ButtonRelease-1> {ArrowButton::_release %W}
1707    bind BwArrowButtonC <Key-space>       {ArrowButton::invoke %W; break}
1708    bind BwArrowButtonC <Return>          {ArrowButton::invoke %W; break}
1709    bind BwArrowButton <Configure>       {ArrowButton::_redraw_whole %W %w %h}
1710    bind BwArrowButton <Destroy>         {ArrowButton::_destroy %W}
1711
1712    variable _grab
1713    variable _moved
1714
1715    array set _grab {current "" pressed "" oldstate "normal" oldrelief ""}
1716}
1717
1718proc ArrowButton::create { path args } {
1719    # Initialize configuration mappings and parse arguments
1720    array set submaps [list ArrowButton [list ] .c [list ]]
1721    array set submaps [Widget::parseArgs ArrowButton $args]
1722
1723    # Create the class frame (so we can do the option db queries)
1724    frame $path -class ArrowButton -borderwidth 0 -highlightthickness 0
1725    Widget::initFromODB ArrowButton $path $submaps(ArrowButton)
1726
1727    # Create the canvas with the initial options
1728    eval [list canvas $path.c] $submaps(.c)
1729
1730    # Compute the width and height of the canvas from the width/height
1731    # of the ArrowButton and the borderwidth/hightlightthickness.
1732    set w   [Widget::getMegawidgetOption $path -width]
1733    set h   [Widget::getMegawidgetOption $path -height]
1734    set bd  [Widget::cget $path -borderwidth]
1735    set ht  [Widget::cget $path -highlightthickness]
1736    set pad [expr {2*($bd+$ht)}]
1737
1738    $path.c configure -width [expr {$w-$pad}] -height [expr {$h-$pad}]
1739    bindtags $path [list $path BwArrowButton [winfo toplevel $path] all]
1740    bindtags $path.c [list $path.c BwArrowButtonC [winfo toplevel $path.c] all]
1741    pack $path.c -expand yes -fill both
1742
1743    set ::ArrowButton::_moved($path) 0
1744
1745    return [Widget::create ArrowButton $path]
1746}
1747
1748proc ArrowButton::configure { path args } {
1749    set res [Widget::configure $path $args]
1750
1751    set ch1 [expr {[Widget::hasChanged $path -width  w] |
1752                   [Widget::hasChanged $path -height h] |
1753                   [Widget::hasChanged $path -borderwidth bd] |
1754                   [Widget::hasChanged $path -highlightthickness ht]}]
1755    set ch2 [expr {[Widget::hasChanged $path -type    val] |
1756                   [Widget::hasChanged $path -ipadx   val] |
1757                   [Widget::hasChanged $path -ipady   val] |
1758                   [Widget::hasChanged $path -arrowbd val] |
1759                   [Widget::hasChanged $path -clean   val] |
1760                   [Widget::hasChanged $path -dir     val]}]
1761
1762    if { $ch1 } {
1763        set pad [expr {2*($bd+$ht)}]
1764        $path.c configure \
1765            -width [expr {$w-$pad}] -height [expr {$h-$pad}] \
1766            -borderwidth $bd -highlightthickness $ht
1767	set ch2 1
1768    }
1769    if { $ch2 } {
1770        _redraw_whole $path [winfo width $path] [winfo height $path]
1771    } else {
1772        _redraw_relief $path
1773        _redraw_state $path
1774    }
1775
1776    return $res
1777}
1778
1779proc ArrowButton::cget { path option } {
1780    return [Widget::cget $path $option]
1781}
1782
1783proc ArrowButton::invoke { path } {
1784    if { ![string equal [winfo class $path] "ArrowButton"] } {
1785	set path [winfo parent $path]
1786    }
1787    if { ![string equal [Widget::getoption $path -state] "disabled"] } {
1788        set oldstate [Widget::getoption $path -state]
1789        if { [string equal [Widget::getoption $path -type] "button"] } {
1790            set oldrelief [Widget::getoption $path -relief]
1791            configure $path -state active -relief sunken
1792        } else {
1793            set oldrelief [Widget::getoption $path -arrowrelief]
1794            configure $path -state active -arrowrelief sunken
1795        }
1796	update idletasks
1797        if {[llength [set cmd [Widget::getoption $path -armcommand]]]} {
1798            uplevel \#0 $cmd
1799        }
1800	after 10
1801        if { [string equal [Widget::getoption $path -type] "button"] } {
1802            configure $path -state $oldstate -relief $oldrelief
1803        } else {
1804            configure $path -state $oldstate -arrowrelief $oldrelief
1805        }
1806        if {[llength [set cmd [Widget::getoption $path -disarmcommand]]]} {
1807            uplevel \#0 $cmd
1808        }
1809        if {[llength [set cmd [Widget::getoption $path -command]]]} {
1810            uplevel \#0 $cmd
1811        }
1812    }
1813}
1814
1815proc ArrowButton::_redraw { path width height } {
1816    variable _moved
1817
1818    set _moved($path) 0
1819    set type  [Widget::getoption $path -type]
1820    set dir   [Widget::getoption $path -dir]
1821    set bd    [expr {[$path.c cget -borderwidth] + [$path.c cget -highlightthickness] + 1}]
1822    set clean [Widget::getoption $path -clean]
1823    if { [string equal $type "arrow"] } {
1824        if { [set id [$path.c find withtag rect]] == "" } {
1825            $path.c create rectangle $bd $bd [expr {$width-$bd-1}] [expr {$height-$bd-1}] -tags rect
1826        } else {
1827            $path.c coords $id $bd $bd [expr {$width-$bd-1}] [expr {$height-$bd-1}]
1828        }
1829        $path.c lower rect
1830        set arrbd [Widget::getoption $path -arrowbd]
1831        set bd    [expr {$bd+$arrbd-1}]
1832    } else {
1833        $path.c delete rect
1834    }
1835    # w and h are max width and max height of arrow
1836    set w [expr {$width  - 2*([Widget::getoption $path -ipadx]+$bd)}]
1837    set h [expr {$height - 2*([Widget::getoption $path -ipady]+$bd)}]
1838
1839    if { $w < 2 } {set w 2}
1840    if { $h < 2 } {set h 2}
1841
1842    if { $clean > 0 } {
1843        # arrange for base to be odd
1844        if { [string equal $dir "top"] || [string equal $dir "bottom"] } {
1845            if { !($w % 2) } {
1846                incr w -1
1847            }
1848            if { $clean == 2 } {
1849                # arrange for h = (w+1)/2
1850                set h2 [expr {($w+1)/2}]
1851                if { $h2 > $h } {
1852                    set w [expr {2*$h-1}]
1853                } else {
1854                    set h $h2
1855                }
1856            }
1857        } else {
1858            if { !($h % 2) } {
1859                incr h -1
1860            }
1861            if { $clean == 2 } {
1862                # arrange for w = (h+1)/2
1863                set w2 [expr {($h+1)/2}]
1864                if { $w2 > $w } {
1865                    set h [expr {2*$w-1}]
1866                } else {
1867                    set w $w2
1868                }
1869            }
1870        }
1871    }
1872
1873    set x0 [expr {($width-$w)/2}]
1874    set y0 [expr {($height-$h)/2}]
1875    set x1 [expr {$x0+$w-1}]
1876    set y1 [expr {$y0+$h-1}]
1877
1878    switch $dir {
1879        top {
1880            set xd [expr {($x0+$x1)/2}]
1881            if { [set id [$path.c find withtag poly]] == "" } {
1882                $path.c create polygon $x0 $y1 $x1 $y1 $xd $y0 -tags poly
1883            } else {
1884                $path.c coords $id $x0 $y1 $x1 $y1 $xd $y0
1885            }
1886            if { [string equal $type "arrow"] } {
1887                if { [set id [$path.c find withtag bot]] == "" } {
1888                    $path.c create line $x0 $y1 $x1 $y1 $xd $y0 -tags bot
1889                } else {
1890                    $path.c coords $id $x0 $y1 $x1 $y1 $xd $y0
1891                }
1892                if { [set id [$path.c find withtag top]] == "" } {
1893                    $path.c create line $x0 $y1 $xd $y0 -tags top
1894                } else {
1895                    $path.c coords $id $x0 $y1 $xd $y0
1896                }
1897                $path.c itemconfigure top -width $arrbd
1898                $path.c itemconfigure bot -width $arrbd
1899            } else {
1900                $path.c delete top
1901                $path.c delete bot
1902            }
1903        }
1904        bottom {
1905            set xd [expr {($x0+$x1)/2}]
1906            if { [set id [$path.c find withtag poly]] == "" } {
1907                $path.c create polygon $x1 $y0 $x0 $y0 $xd $y1 -tags poly
1908            } else {
1909                $path.c coords $id $x1 $y0 $x0 $y0 $xd $y1
1910            }
1911            if { [string equal $type "arrow"] } {
1912                if { [set id [$path.c find withtag top]] == "" } {
1913                    $path.c create line $x1 $y0 $x0 $y0 $xd $y1 -tags top
1914                } else {
1915                    $path.c coords $id $x1 $y0 $x0 $y0 $xd $y1
1916                }
1917                if { [set id [$path.c find withtag bot]] == "" } {
1918                    $path.c create line $x1 $y0 $xd $y1 -tags bot
1919                } else {
1920                    $path.c coords $id $x1 $y0 $xd $y1
1921                }
1922                $path.c itemconfigure top -width $arrbd
1923                $path.c itemconfigure bot -width $arrbd
1924            } else {
1925                $path.c delete top
1926                $path.c delete bot
1927            }
1928        }
1929        left {
1930            set yd [expr {($y0+$y1)/2}]
1931            if { [set id [$path.c find withtag poly]] == "" } {
1932                $path.c create polygon $x1 $y0 $x1 $y1 $x0 $yd -tags poly
1933            } else {
1934                $path.c coords $id $x1 $y0 $x1 $y1 $x0 $yd
1935            }
1936            if { [string equal $type "arrow"] } {
1937                if { [set id [$path.c find withtag bot]] == "" } {
1938                    $path.c create line $x1 $y0 $x1 $y1 $x0 $yd -tags bot
1939                } else {
1940                    $path.c coords $id $x1 $y0 $x1 $y1 $x0 $yd
1941                }
1942                if { [set id [$path.c find withtag top]] == "" } {
1943                    $path.c create line $x1 $y0 $x0 $yd -tags top
1944                } else {
1945                    $path.c coords $id $x1 $y0 $x0 $yd
1946                }
1947                $path.c itemconfigure top -width $arrbd
1948                $path.c itemconfigure bot -width $arrbd
1949            } else {
1950                $path.c delete top
1951                $path.c delete bot
1952            }
1953        }
1954        right {
1955            set yd [expr {($y0+$y1)/2}]
1956            if { [set id [$path.c find withtag poly]] == "" } {
1957                $path.c create polygon $x0 $y1 $x0 $y0 $x1 $yd -tags poly
1958            } else {
1959                $path.c coords $id $x0 $y1 $x0 $y0 $x1 $yd
1960            }
1961            if { [string equal $type "arrow"] } {
1962                if { [set id [$path.c find withtag top]] == "" } {
1963                    $path.c create line $x0 $y1 $x0 $y0 $x1 $yd -tags top
1964                } else {
1965                    $path.c coords $id $x0 $y1 $x0 $y0 $x1 $yd
1966                }
1967                if { [set id [$path.c find withtag bot]] == "" } {
1968                    $path.c create line $x0 $y1 $x1 $yd -tags bot
1969                } else {
1970                    $path.c coords $id $x0 $y1 $x1 $yd
1971                }
1972                $path.c itemconfigure top -width $arrbd
1973                $path.c itemconfigure bot -width $arrbd
1974            } else {
1975                $path.c delete top
1976                $path.c delete bot
1977            }
1978        }
1979    }
1980}
1981
1982proc ArrowButton::_redraw_state { path } {
1983    set state [Widget::getoption $path -state]
1984    if { [string equal [Widget::getoption $path -type] "button"] } {
1985        switch $state {
1986            normal   {set bg -background;       set fg -foreground}
1987            active   {set bg -activebackground; set fg -activeforeground}
1988            disabled {set bg -background;       set fg -disabledforeground}
1989        }
1990        set fg [Widget::getoption $path $fg]
1991        $path.c configure -background [Widget::getoption $path $bg]
1992        $path.c itemconfigure poly -fill $fg -outline $fg
1993    } else {
1994        switch $state {
1995            normal   {set stipple "";     set bg [Widget::getoption $path -background] }
1996            active   {set stipple "";     set bg [Widget::getoption $path -activebackground] }
1997            disabled {set stipple gray50; set bg black }
1998        }
1999        set thrc [Widget::getoption $path -troughcolor]
2000        $path.c configure -background [Widget::getoption $path -background]
2001        $path.c itemconfigure rect -fill $thrc -outline $thrc
2002        $path.c itemconfigure poly -fill $bg   -outline $bg -stipple $stipple
2003    }
2004}
2005
2006proc ArrowButton::_redraw_relief { path } {
2007    variable _moved
2008
2009    if { [string equal [Widget::getoption $path -type] "button"] } {
2010        if { [string equal [Widget::getoption $path -relief] "sunken"] } {
2011            if { !$_moved($path) } {
2012                $path.c move poly 1 1
2013                set _moved($path) 1
2014            }
2015        } else {
2016            if { $_moved($path) } {
2017                $path.c move poly -1 -1
2018                set _moved($path) 0
2019            }
2020        }
2021    } else {
2022        set col3d [BWidget::get3dcolor $path [Widget::getoption $path -background]]
2023        switch [Widget::getoption $path -arrowrelief] {
2024            raised {set top [lindex $col3d 1]; set bot [lindex $col3d 0]}
2025            sunken {set top [lindex $col3d 0]; set bot [lindex $col3d 1]}
2026        }
2027        $path.c itemconfigure top -fill $top
2028        $path.c itemconfigure bot -fill $bot
2029    }
2030}
2031
2032proc ArrowButton::_redraw_whole { path width height } {
2033    _redraw $path $width $height
2034    _redraw_relief $path
2035    _redraw_state $path
2036}
2037
2038proc ArrowButton::_enter { path } {
2039    variable _grab
2040    set path [winfo parent $path]
2041    set _grab(current) $path
2042    if { ![string equal [Widget::getoption $path -state] "disabled"] } {
2043        set _grab(oldstate) [Widget::getoption $path -state]
2044        configure $path -state active
2045        if { $_grab(pressed) == $path } {
2046            if { [string equal [Widget::getoption $path -type] "button"] } {
2047                set _grab(oldrelief) [Widget::getoption $path -relief]
2048                configure $path -relief sunken
2049            } else {
2050                set _grab(oldrelief) [Widget::getoption $path -arrowrelief]
2051                configure $path -arrowrelief sunken
2052            }
2053        }
2054    }
2055}
2056
2057proc ArrowButton::_leave { path } {
2058    variable _grab
2059    set path [winfo parent $path]
2060    set _grab(current) ""
2061    if { ![string equal [Widget::getoption $path -state] "disabled"] } {
2062        configure $path -state $_grab(oldstate)
2063        if { $_grab(pressed) == $path } {
2064            if { [string equal [Widget::getoption $path -type] "button"] } {
2065                configure $path -relief $_grab(oldrelief)
2066            } else {
2067                configure $path -arrowrelief $_grab(oldrelief)
2068            }
2069        }
2070    }
2071}
2072
2073proc ArrowButton::_press { path } {
2074    variable _grab
2075    set path [winfo parent $path]
2076    if { ![string equal [Widget::getoption $path -state] "disabled"] } {
2077        set _grab(pressed) $path
2078            if { [string equal [Widget::getoption $path -type] "button"] } {
2079            set _grab(oldrelief) [Widget::getoption $path -relief]
2080            configure $path -relief sunken
2081        } else {
2082            set _grab(oldrelief) [Widget::getoption $path -arrowrelief]
2083            configure $path -arrowrelief sunken
2084        }
2085        if {[llength [set cmd [Widget::getoption $path -armcommand]]]} {
2086            uplevel \#0 $cmd
2087            if { [set delay [Widget::getoption $path -repeatdelay]]    > 0 ||
2088                 [set delay [Widget::getoption $path -repeatinterval]] > 0 } {
2089                after $delay [list ArrowButton::_repeat $path]
2090            }
2091        }
2092    }
2093}
2094
2095proc ArrowButton::_release { path } {
2096    variable _grab
2097    set path [winfo parent $path]
2098    if { $_grab(pressed) == $path } {
2099        set _grab(pressed) ""
2100            if { [string equal [Widget::getoption $path -type] "button"] } {
2101            configure $path -relief $_grab(oldrelief)
2102        } else {
2103            configure $path -arrowrelief $_grab(oldrelief)
2104        }
2105        if {[llength [set cmd [Widget::getoption $path -disarmcommand]]]} {
2106            uplevel \#0 $cmd
2107        }
2108        if { $_grab(current) == $path &&
2109             ![string equal [Widget::getoption $path -state] "disabled"] &&
2110             [llength [set cmd [Widget::getoption $path -command]]]} {
2111            uplevel \#0 $cmd
2112        }
2113    }
2114}
2115
2116proc ArrowButton::_repeat { path } {
2117    variable _grab
2118    if { $_grab(current) == $path && $_grab(pressed) == $path &&
2119         ![string equal [Widget::getoption $path -state] "disabled"] &&
2120         [llength [set cmd [Widget::getoption $path -armcommand]]]} {
2121        uplevel \#0 $cmd
2122    }
2123    if { $_grab(pressed) == $path &&
2124         ([set delay [Widget::getoption $path -repeatinterval]] > 0 ||
2125          [set delay [Widget::getoption $path -repeatdelay]]    > 0) } {
2126        after $delay [list ArrowButton::_repeat $path]
2127    }
2128}
2129
2130proc ArrowButton::_destroy { path } {
2131    variable _moved
2132    Widget::destroy $path
2133    unset _moved($path)
2134}
2135# ---------------------------------------------------------------------------
2136#  notebook.tcl -- part of Unifix BWidget Toolkit
2137# ---------------------------------------------------------------------------
2138
2139namespace eval NoteBook {
2140    Widget::define NoteBook notebook ArrowButton
2141
2142    namespace eval Page {
2143        Widget::declare NoteBook::Page {
2144            {-state      Enum       normal 0 {normal disabled}}
2145            {-createcmd  String     ""     0}
2146            {-raisecmd   String     ""     0}
2147            {-leavecmd   String     ""     0}
2148            {-image      TkResource ""     0 label}
2149            {-text       String     ""     0}
2150            {-foreground         String     ""     0}
2151            {-background         String     ""     0}
2152            {-activeforeground   String     ""     0}
2153            {-activebackground   String     ""     0}
2154            {-disabledforeground String     ""     0}
2155        }
2156    }
2157
2158    Widget::bwinclude NoteBook ArrowButton .c.fg \
2159	    include {-foreground -background -activeforeground \
2160		-activebackground -disabledforeground -repeatinterval \
2161		-repeatdelay -borderwidth} \
2162	    initialize {-borderwidth 1}
2163    Widget::bwinclude NoteBook ArrowButton .c.fd \
2164	    include {-foreground -background -activeforeground \
2165		-activebackground -disabledforeground -repeatinterval \
2166		-repeatdelay -borderwidth} \
2167	    initialize {-borderwidth 1}
2168
2169    Widget::declare NoteBook {
2170	{-foreground		TkResource "" 0 button}
2171        {-background		TkResource "" 0 button}
2172        {-activebackground	TkResource "" 0 button}
2173        {-activeforeground	TkResource "" 0 button}
2174        {-disabledforeground	TkResource "" 0 button}
2175        {-font			TkResource "" 0 button}
2176        {-side			Enum       top 0 {top bottom}}
2177        {-homogeneous		Boolean 0   0}
2178        {-borderwidth		Int 1   0 "%d >= 1 && %d <= 2"}
2179 	{-internalborderwidth	Int 10  0 "%d >= 0"}
2180        {-width			Int 0   0 "%d >= 0"}
2181        {-height		Int 0   0 "%d >= 0"}
2182
2183        {-repeatdelay        BwResource ""  0 ArrowButton}
2184        {-repeatinterval     BwResource ""  0 ArrowButton}
2185
2186        {-fg                 Synonym -foreground}
2187        {-bg                 Synonym -background}
2188        {-bd                 Synonym -borderwidth}
2189        {-ibd                Synonym -internalborderwidth}
2190
2191	{-arcradius          Int     2     0 "%d >= 0 && %d <= 8"}
2192	{-tabbevelsize       Int     0     0 "%d >= 0 && %d <= 8"}
2193        {-tabpady            Padding {0 6} 0 "%d >= 0"}
2194    }
2195
2196    Widget::addmap NoteBook "" .c {-background {}}
2197
2198    variable _warrow 12
2199
2200    bind NoteBook <Configure> [list NoteBook::_resize  %W]
2201    bind NoteBook <Destroy>   [list NoteBook::_destroy %W]
2202}
2203
2204proc NoteBook::create { path args } {
2205    variable $path
2206    upvar 0  $path data
2207
2208    Widget::init NoteBook $path $args
2209
2210    set data(base)     0
2211    set data(select)   ""
2212    set data(pages)    {}
2213    set data(pages)    {}
2214    set data(cpt)      0
2215    set data(realized) 0
2216    set data(wpage)    0
2217
2218    _compute_height $path
2219
2220    # Create the canvas
2221    set w [expr {[Widget::cget $path -width]+4}]
2222    set h [expr {[Widget::cget $path -height]+$data(hpage)+4}]
2223
2224    frame $path -class NoteBook -borderwidth 0 -highlightthickness 0 \
2225	    -relief flat
2226    eval [list canvas $path.c] [Widget::subcget $path .c] \
2227	    [list -relief flat -borderwidth 0 -highlightthickness 0 \
2228	    -width $w -height $h]
2229    pack $path.c -expand yes -fill both
2230
2231    # Removing the Canvas global bindings from our canvas as
2232    # application specific bindings on that tag may interfere with its
2233    # operation here. [SF item #459033]
2234
2235    set bindings [bindtags $path.c]
2236    set pos [lsearch -exact $bindings Canvas]
2237    if {$pos >= 0} {
2238	set bindings [lreplace $bindings $pos $pos]
2239    }
2240    bindtags $path.c $bindings
2241
2242    # Create the arrow button
2243    eval [list ArrowButton::create $path.c.fg] [Widget::subcget $path .c.fg] \
2244	    [list -highlightthickness 0 -type button -dir left \
2245	    -armcommand [list NoteBook::_xview $path -1]]
2246
2247    eval [list ArrowButton::create $path.c.fd] [Widget::subcget $path .c.fd] \
2248	    [list -highlightthickness 0 -type button -dir right \
2249	    -armcommand [list NoteBook::_xview $path 1]]
2250
2251    Widget::create NoteBook $path
2252
2253    set bg [Widget::cget $path -background]
2254    foreach {data(dbg) data(lbg)} [BWidget::get3dcolor $path $bg] {break}
2255
2256    return $path
2257}
2258
2259proc NoteBook::configure { path args } {
2260    variable $path
2261    upvar 0  $path data
2262
2263    set res [Widget::configure $path $args]
2264    set redraw 0
2265    set opts [list -font -homogeneous -tabpady]
2266    foreach {cf ch cp} [eval Widget::hasChangedX $path $opts] {break}
2267    if {$cf || $ch || $cp} {
2268        if { $cf || $cp } {
2269            _compute_height $path
2270        }
2271        _compute_width $path
2272        set redraw 1
2273    }
2274    set chibd [Widget::hasChanged $path -internalborderwidth ibd]
2275    set chbg  [Widget::hasChanged $path -background bg]
2276    if {$chibd || $chbg} {
2277        foreach page $data(pages) {
2278            $path.f$page configure \
2279                -borderwidth $ibd -background $bg
2280        }
2281    }
2282
2283    if {$chbg} {
2284        set col [BWidget::get3dcolor $path $bg]
2285        set data(dbg)  [lindex $col 0]
2286        set data(lbg)  [lindex $col 1]
2287        set redraw 1
2288    }
2289    if { [Widget::hasChanged $path -foreground  fg] ||
2290         [Widget::hasChanged $path -borderwidth bd] ||
2291	 [Widget::hasChanged $path -arcradius radius] ||
2292         [Widget::hasChanged $path -tabbevelsize bevel] ||
2293         [Widget::hasChanged $path -side side] } {
2294        set redraw 1
2295    }
2296    set wc [Widget::hasChanged $path -width  w]
2297    set hc [Widget::hasChanged $path -height h]
2298    if { $wc || $hc } {
2299        $path.c configure \
2300		-width  [expr {$w + 4}] \
2301		-height [expr {$h + $data(hpage) + 4}]
2302    }
2303    if { $redraw } {
2304        _redraw $path
2305    }
2306
2307    return $res
2308}
2309
2310proc NoteBook::cget { path option } {
2311    return [Widget::cget $path $option]
2312}
2313
2314proc NoteBook::compute_size { path } {
2315    variable $path
2316    upvar 0  $path data
2317
2318    set wmax 0
2319    set hmax 0
2320    update idletasks
2321    foreach page $data(pages) {
2322        set w    [winfo reqwidth  $path.f$page]
2323        set h    [winfo reqheight $path.f$page]
2324        set wmax [expr {$w>$wmax ? $w : $wmax}]
2325        set hmax [expr {$h>$hmax ? $h : $hmax}]
2326    }
2327    configure $path -width $wmax -height $hmax
2328    # Sven... well ok so this is called twice in some cases...
2329    NoteBook::_redraw $path
2330    # Sven end
2331}
2332
2333proc NoteBook::insert { path index page args } {
2334    variable $path
2335    upvar 0  $path data
2336
2337    if { [lsearch -exact $data(pages) $page] != -1 } {
2338        return -code error "page \"$page\" already exists"
2339    }
2340
2341    set f $path.f$page
2342    Widget::init NoteBook::Page $f $args
2343
2344    set data(pages) [linsert $data(pages) $index $page]
2345    # If the page doesn't exist, create it; if it does reset its bg and ibd
2346    if { ![winfo exists $f] } {
2347        frame $f \
2348	    -relief      flat \
2349	    -background  [Widget::cget $path -background] \
2350	    -borderwidth [Widget::cget $path -internalborderwidth]
2351        set data($page,realized) 0
2352    } else {
2353	$f configure \
2354	    -background  [Widget::cget $path -background] \
2355	    -borderwidth [Widget::cget $path -internalborderwidth]
2356    }
2357    _compute_height $path
2358    _compute_width  $path
2359    _draw_page $path $page 1
2360    _redraw $path
2361
2362    return $f
2363}
2364
2365proc NoteBook::delete { path page {destroyframe 1} } {
2366    variable $path
2367    upvar 0  $path data
2368
2369    set pos [_test_page $path $page]
2370    set data(pages) [lreplace $data(pages) $pos $pos]
2371    _compute_width $path
2372    $path.c delete p:$page
2373    if { $data(select) == $page } {
2374        set data(select) ""
2375    }
2376    if { $pos < $data(base) } {
2377        incr data(base) -1
2378    }
2379    if { $destroyframe } {
2380        destroy $path.f$page
2381        unset data($page,width) data($page,realized)
2382    }
2383    _redraw $path
2384}
2385
2386proc NoteBook::itemconfigure { path page args } {
2387    _test_page $path $page
2388    set res [_itemconfigure $path $page $args]
2389    _redraw $path
2390
2391    return $res
2392}
2393
2394proc NoteBook::itemcget { path page option } {
2395    _test_page $path $page
2396    return [Widget::cget $path.f$page $option]
2397}
2398
2399proc NoteBook::bindtabs { path event script } {
2400    if { $script != "" } {
2401	append script " \[NoteBook::_get_page_name [list $path] current 1\]"
2402        $path.c bind "page" $event $script
2403    } else {
2404        $path.c bind "page" $event {}
2405    }
2406}
2407
2408proc NoteBook::move { path page index } {
2409    variable $path
2410    upvar 0  $path data
2411
2412    set pos [_test_page $path $page]
2413    set data(pages) [linsert [lreplace $data(pages) $pos $pos] $index $page]
2414    _redraw $path
2415}
2416
2417proc NoteBook::raise { path {page ""} } {
2418    variable $path
2419    upvar 0  $path data
2420
2421    if { $page != "" } {
2422        _test_page $path $page
2423        _select $path $page
2424    }
2425    return $data(select)
2426}
2427
2428proc NoteBook::see { path page } {
2429    variable $path
2430    upvar 0  $path data
2431
2432    set pos [_test_page $path $page]
2433    if { $pos < $data(base) } {
2434        set data(base) $pos
2435        _redraw $path
2436    } else {
2437        set w     [expr {[winfo width $path]-1}]
2438        set fpage [expr {[_get_x_page $path $pos] + $data($page,width) + 6}]
2439        set idx   $data(base)
2440        while { $idx < $pos && $fpage > $w } {
2441            set fpage [expr {$fpage - $data([lindex $data(pages) $idx],width)}]
2442            incr idx
2443        }
2444        if { $idx != $data(base) } {
2445            set data(base) $idx
2446            _redraw $path
2447        }
2448    }
2449}
2450
2451proc NoteBook::page { path first {last ""} } {
2452    variable $path
2453    upvar 0  $path data
2454
2455    if { $last == "" } {
2456        return [lindex $data(pages) $first]
2457    } else {
2458        return [lrange $data(pages) $first $last]
2459    }
2460}
2461
2462proc NoteBook::pages { path {first ""} {last ""}} {
2463    variable $path
2464    upvar 0  $path data
2465
2466    if { ![string length $first] } {
2467	return $data(pages)
2468    }
2469
2470    if { ![string length $last] } {
2471        return [lindex $data(pages) $first]
2472    } else {
2473        return [lrange $data(pages) $first $last]
2474    }
2475}
2476
2477proc NoteBook::index { path page } {
2478    variable $path
2479    upvar 0  $path data
2480
2481    return [lsearch -exact $data(pages) $page]
2482}
2483
2484proc NoteBook::_destroy { path } {
2485    variable $path
2486    upvar 0  $path data
2487
2488    foreach page $data(pages) {
2489        Widget::destroy $path.f$page
2490    }
2491    Widget::destroy $path
2492    unset data
2493}
2494
2495proc NoteBook::getframe { path page } {
2496    return $path.f$page
2497}
2498
2499proc NoteBook::_test_page { path page } {
2500    variable $path
2501    upvar 0  $path data
2502
2503    if { [set pos [lsearch -exact $data(pages) $page]] == -1 } {
2504        return -code error "page \"$page\" does not exists"
2505    }
2506    return $pos
2507}
2508
2509proc NoteBook::_getoption { path page option } {
2510    set value [Widget::cget $path.f$page $option]
2511    if {![string length $value]} {
2512        set value [Widget::cget $path $option]
2513    }
2514    return $value
2515}
2516
2517proc NoteBook::_itemconfigure { path page lres } {
2518    variable $path
2519    upvar 0  $path data
2520
2521    set res [Widget::configure $path.f$page $lres]
2522    if { [Widget::hasChanged $path.f$page -text foo] } {
2523        _compute_width $path
2524    } elseif  { [Widget::hasChanged $path.f$page -image foo] } {
2525        _compute_height $path
2526        _compute_width  $path
2527    }
2528    if { [Widget::hasChanged $path.f$page -state state] &&
2529         $state == "disabled" && $data(select) == $page } {
2530        set data(select) ""
2531    }
2532    return $res
2533}
2534
2535proc NoteBook::_compute_width { path } {
2536    variable $path
2537    upvar 0  $path data
2538
2539    set wmax 0
2540    set wtot 0
2541    set hmax $data(hpage)
2542    set font [Widget::cget $path -font]
2543    if { ![info exists data(textid)] } {
2544        set data(textid) [$path.c create text 0 -100 -font $font -anchor nw]
2545    }
2546    set id $data(textid)
2547    $path.c itemconfigure $id -font $font
2548    foreach page $data(pages) {
2549        $path.c itemconfigure $id -text [Widget::cget $path.f$page -text]
2550	# Get the bbox for this text to determine its width, then substract
2551	# 6 from the width to account for canvas bbox oddness w.r.t. widths of
2552	# simple text.
2553	foreach {x1 y1 x2 y2} [$path.c bbox $id] break
2554	set x2 [expr {$x2 - 6}]
2555        set wtext [expr {$x2 - $x1 + 20}]
2556        if { [set img [Widget::cget $path.f$page -image]] != "" } {
2557            set wtext [expr {$wtext + [image width $img] + 4}]
2558            set himg  [expr {[image height $img] + 6}]
2559            if { $himg > $hmax } {
2560                set hmax $himg
2561            }
2562        }
2563        set  wmax  [expr {$wtext > $wmax ? $wtext : $wmax}]
2564        incr wtot  $wtext
2565        set  data($page,width) $wtext
2566    }
2567    if { [Widget::cget $path -homogeneous] } {
2568        foreach page $data(pages) {
2569            set data($page,width) $wmax
2570        }
2571        set wtot [expr {$wmax * [llength $data(pages)]}]
2572    }
2573    set data(hpage) $hmax
2574    set data(wpage) $wtot
2575}
2576
2577proc NoteBook::_compute_height { path } {
2578    variable $path
2579    upvar 0  $path data
2580
2581    set font    [Widget::cget $path -font]
2582    set pady0   [Widget::_get_padding $path -tabpady 0]
2583    set pady1   [Widget::_get_padding $path -tabpady 1]
2584    set metrics [font metrics $font -linespace]
2585    set imgh    0
2586    set lines   1
2587    foreach page $data(pages) {
2588        set img  [Widget::cget $path.f$page -image]
2589        set text [Widget::cget $path.f$page -text]
2590        set len [llength [split $text \n]]
2591        if {$len > $lines} { set lines $len}
2592        if {$img != ""} {
2593            set h [image height $img]
2594            if {$h > $imgh} { set imgh $h }
2595        }
2596    }
2597    set height [expr {$metrics * $lines}]
2598    if {$imgh > $height} { set height $imgh }
2599    set data(hpage) [expr {$height + $pady0 + $pady1}]
2600}
2601
2602proc NoteBook::_get_x_page { path pos } {
2603    variable _warrow
2604    variable $path
2605    upvar 0  $path data
2606
2607    set base $data(base)
2608    # notebook tabs start flush with the left side of the notebook
2609    set x 0
2610    if { $pos < $base } {
2611        foreach page [lrange $data(pages) $pos [expr {$base-1}]] {
2612            incr x [expr {-$data($page,width)}]
2613        }
2614    } elseif { $pos > $base } {
2615        foreach page [lrange $data(pages) $base [expr {$pos-1}]] {
2616            incr x $data($page,width)
2617        }
2618    }
2619    return $x
2620}
2621
2622proc NoteBook::_xview { path inc } {
2623    variable $path
2624    upvar 0  $path data
2625
2626    if { $inc == -1 } {
2627        set base [expr {$data(base)-1}]
2628        set dx $data([lindex $data(pages) $base],width)
2629    } else {
2630        set dx [expr {-$data([lindex $data(pages) $data(base)],width)}]
2631        set base [expr {$data(base)+1}]
2632    }
2633
2634    if { $base >= 0 && $base < [llength $data(pages)] } {
2635        set data(base) $base
2636        $path.c move page $dx 0
2637        _draw_area   $path
2638        _draw_arrows $path
2639    }
2640}
2641
2642proc NoteBook::_highlight { type path page } {
2643    variable $path
2644    upvar 0  $path data
2645
2646    if { [string equal [Widget::cget $path.f$page -state] "disabled"] } {
2647        return
2648    }
2649
2650    switch -- $type {
2651        on {
2652            $path.c itemconfigure "$page:poly" \
2653		    -fill [_getoption $path $page -activebackground]
2654            $path.c itemconfigure "$page:text" \
2655		    -fill [_getoption $path $page -activeforeground]
2656        }
2657        off {
2658            $path.c itemconfigure "$page:poly" \
2659		    -fill [_getoption $path $page -background]
2660            $path.c itemconfigure "$page:text" \
2661		    -fill [_getoption $path $page -foreground]
2662        }
2663    }
2664}
2665
2666proc NoteBook::_select { path page } {
2667    variable $path
2668    upvar 0  $path data
2669
2670    if {![string equal [Widget::cget $path.f$page -state] "normal"]} { return }
2671
2672    set oldsel $data(select)
2673
2674    if {[string equal $page $oldsel]} { return }
2675
2676    if { ![string equal $oldsel ""] } {
2677	set cmd [Widget::cget $path.f$oldsel -leavecmd]
2678	if { ![string equal $cmd ""] } {
2679	    set code [catch {uplevel \#0 $cmd} res]
2680	    if { $code == 1 || $res == 0 } {
2681		return -code $code $res
2682	    }
2683	}
2684	set data(select) ""
2685	_draw_page $path $oldsel 0
2686    }
2687
2688    set data(select) $page
2689    if { ![string equal $page ""] } {
2690	if { !$data($page,realized) } {
2691	    set data($page,realized) 1
2692	    set cmd [Widget::cget $path.f$page -createcmd]
2693	    if { ![string equal $cmd ""] } {
2694		uplevel \#0 $cmd
2695	    }
2696	}
2697	set cmd [Widget::cget $path.f$page -raisecmd]
2698	if { ![string equal $cmd ""] } {
2699	    uplevel \#0 $cmd
2700	}
2701	_draw_page $path $page 0
2702    }
2703
2704    _draw_area $path
2705}
2706
2707proc NoteBook::_redraw { path } {
2708    variable $path
2709    upvar 0  $path data
2710
2711    if { !$data(realized) } { return }
2712
2713    _compute_height $path
2714
2715    foreach page $data(pages) {
2716        _draw_page $path $page 0
2717    }
2718    _draw_area   $path
2719    _draw_arrows $path
2720}
2721
2722proc NoteBook::_draw_page { path page create } {
2723    variable $path
2724    upvar 0  $path data
2725
2726    # --- calcul des coordonnees et des couleurs de l'onglet ------------------
2727    set pos [lsearch -exact $data(pages) $page]
2728    set bg  [_getoption $path $page -background]
2729
2730    # lookup the tab colors
2731    set fgt   $data(lbg)
2732    set fgb   $data(dbg)
2733
2734    set h   $data(hpage)
2735    set xd  [_get_x_page $path $pos]
2736    set xf  [expr {$xd + $data($page,width)}]
2737
2738    # Set the initial text offsets -- a few pixels down, centered left-to-right
2739    set textOffsetY [expr [Widget::_get_padding $path -tabpady 0] + 3]
2740    set textOffsetX 9
2741
2742    set top		2
2743    set arcRadius	[Widget::cget $path -arcradius]
2744    set xBevel		[Widget::cget $path -tabbevelsize]
2745
2746    if { $data(select) != $page } {
2747	if { $pos == 0 } {
2748	    # The leftmost page is a special case -- it is drawn with its
2749	    # tab a little indented.  To achieve this, we incr xd.  We also
2750	    # decr textOffsetX, so that the text doesn't move left/right.
2751	    incr xd 2
2752	    incr textOffsetX -2
2753	}
2754    } else {
2755	# The selected page's text is raised higher than the others
2756	incr top -2
2757    }
2758
2759    # Precompute some coord values that we use a lot
2760    set topPlusRadius	[expr {$top + $arcRadius}]
2761    set rightPlusRadius	[expr {$xf + $arcRadius}]
2762    set leftPlusRadius	[expr {$xd + $arcRadius}]
2763
2764    # Sven
2765    set side [Widget::cget $path -side]
2766    set tabsOnBottom [string equal $side "bottom"]
2767
2768    set h1 [expr {[winfo height $path]}]
2769    set bd [Widget::cget $path -borderwidth]
2770    if {$bd < 1} { set bd 1 }
2771
2772    if { $tabsOnBottom } {
2773	# adjust to keep bottom edge in view
2774	incr h1 -1
2775	set top [expr {$top * -1}]
2776	set topPlusRadius [expr {$topPlusRadius * -1}]
2777	# Hrm... the canvas has an issue with drawing diagonal segments
2778	# of lines from the bottom to the top, so we have to draw this line
2779	# backwards (ie, lt is actually the bottom, drawn from right to left)
2780        set lt  [list \
2781		$rightPlusRadius			[expr {$h1-$h-1}] \
2782		[expr {$rightPlusRadius - $xBevel}]	[expr {$h1 + $topPlusRadius}] \
2783		[expr {$xf - $xBevel}]			[expr {$h1 + $top}] \
2784		[expr {$leftPlusRadius + $xBevel}]	[expr {$h1 + $top}] \
2785		]
2786        set lb  [list \
2787		[expr {$leftPlusRadius + $xBevel}]	[expr {$h1 + $top}] \
2788		[expr {$xd + $xBevel}]			[expr {$h1 + $topPlusRadius}] \
2789		$xd					[expr {$h1-$h-1}] \
2790		]
2791	# Because we have to do this funky reverse order thing, we have to
2792	# swap the top/bottom colors too.
2793	set tmp $fgt
2794	set fgt $fgb
2795	set fgb $tmp
2796    } else {
2797	set lt [list \
2798		$xd					$h \
2799		[expr {$xd + $xBevel}]			$topPlusRadius \
2800		[expr {$leftPlusRadius + $xBevel}]	$top \
2801		[expr {$xf + 1 - $xBevel}]		$top \
2802		]
2803	set lb [list \
2804		[expr {$xf + 1 - $xBevel}] 		[expr {$top + 1}] \
2805		[expr {$rightPlusRadius - $xBevel}]	$topPlusRadius \
2806		$rightPlusRadius			$h \
2807		]
2808    }
2809
2810    set img [Widget::cget $path.f$page -image]
2811
2812    set ytext $top
2813    if { $tabsOnBottom } {
2814	# The "+ 2" below moves the text closer to the bottom of the tab,
2815	# so it doesn't look so cramped.  I should be able to achieve the
2816	# same goal by changing the anchor of the text and using this formula:
2817	# ytext = $top + $h1 - $textOffsetY
2818	# but that doesn't quite work (I think the linespace from the text
2819	# gets in the way)
2820	incr ytext [expr {$h1 - $h + 2}]
2821    }
2822    incr ytext $textOffsetY
2823
2824    set xtext [expr {$xd + $textOffsetX}]
2825    if { $img != "" } {
2826	# if there's an image, put it on the left and move the text right
2827	set ximg $xtext
2828	incr xtext [expr {[image width $img] + 2}]
2829    }
2830
2831    if { $data(select) == $page } {
2832        set bd    [Widget::cget $path -borderwidth]
2833	if {$bd < 1} { set bd 1 }
2834        set fg    [_getoption $path $page -foreground]
2835    } else {
2836        set bd    1
2837        if { [Widget::cget $path.f$page -state] == "normal" } {
2838            set fg [_getoption $path $page -foreground]
2839        } else {
2840            set fg [_getoption $path $page -disabledforeground]
2841        }
2842    }
2843
2844    # --- creation ou modification de l'onglet --------------------------------
2845    # Sven
2846    if { $create } {
2847	# Create the tab region
2848        eval [list $path.c create polygon] [concat $lt $lb] [list \
2849		-tags		[list page p:$page $page:poly] \
2850		-outline	$bg \
2851		-fill		$bg \
2852		]
2853        eval [list $path.c create line] $lt [list \
2854            -tags [list page p:$page $page:top top] -fill $fgt -width $bd]
2855        eval [list $path.c create line] $lb [list \
2856            -tags [list page p:$page $page:bot bot] -fill $fgb -width $bd]
2857        $path.c create text $xtext $ytext 			\
2858		-text	[Widget::cget $path.f$page -text]	\
2859		-font	[Widget::cget $path -font]		\
2860		-fill	$fg					\
2861		-anchor	nw					\
2862		-tags	[list page p:$page $page:text]
2863
2864        $path.c bind p:$page <ButtonPress-1> \
2865		[list NoteBook::_select $path $page]
2866        $path.c bind p:$page <Enter> \
2867		[list NoteBook::_highlight on  $path $page]
2868        $path.c bind p:$page <Leave> \
2869		[list NoteBook::_highlight off $path $page]
2870    } else {
2871        $path.c coords "$page:text" $xtext $ytext
2872
2873        $path.c itemconfigure "$page:text" \
2874            -text [Widget::cget $path.f$page -text] \
2875            -font [Widget::cget $path -font] \
2876            -fill $fg
2877    }
2878    eval [list $path.c coords "$page:poly"] [concat $lt $lb]
2879    eval [list $path.c coords "$page:top"]  $lt
2880    eval [list $path.c coords "$page:bot"]  $lb
2881    $path.c itemconfigure "$page:poly" -fill $bg  -outline $bg
2882    $path.c itemconfigure "$page:top"  -fill $fgt -width $bd
2883    $path.c itemconfigure "$page:bot"  -fill $fgb -width $bd
2884
2885    # Sven end
2886
2887    if { $img != "" } {
2888        # Sven
2889	set id [$path.c find withtag $page:img]
2890	if { [string equal $id ""] } {
2891	    set id [$path.c create image $ximg $ytext \
2892		    -anchor nw    \
2893		    -tags   [list page p:$page $page:img]]
2894        }
2895        $path.c coords $id $ximg $ytext
2896        $path.c itemconfigure $id -image $img
2897        # Sven end
2898    } else {
2899        $path.c delete $page:img
2900    }
2901
2902    if { $data(select) == $page } {
2903        $path.c raise p:$page
2904    } elseif { $pos == 0 } {
2905        if { $data(select) == "" } {
2906            $path.c raise p:$page
2907        } else {
2908            $path.c lower p:$page p:$data(select)
2909        }
2910    } else {
2911        set pred [lindex $data(pages) [expr {$pos-1}]]
2912        if { $data(select) != $pred || $pos == 1 } {
2913            $path.c lower p:$page p:$pred
2914        } else {
2915            $path.c lower p:$page p:[lindex $data(pages) [expr {$pos-2}]]
2916        }
2917    }
2918}
2919
2920proc NoteBook::_draw_arrows { path } {
2921    variable _warrow
2922    variable $path
2923    upvar 0  $path data
2924
2925    set w       [expr {[winfo width $path]-1}]
2926    set h       [expr {$data(hpage)-1}]
2927    set nbpages [llength $data(pages)]
2928    set xl      0
2929    set xr      [expr {$w-$_warrow+1}]
2930
2931    set side [Widget::cget $path -side]
2932    if { [string equal $side "bottom"] } {
2933        set h1 [expr {[winfo height $path]-1}]
2934        set bd [Widget::cget $path -borderwidth]
2935	if {$bd < 1} { set bd 1 }
2936        set y0 [expr {$h1 - $data(hpage) + $bd}]
2937    } else {
2938        set y0 1
2939    }
2940
2941    if { $data(base) > 0 } {
2942        # Sven
2943        if { ![llength [$path.c find withtag "leftarrow"]] } {
2944            $path.c create window $xl $y0 \
2945                -width  $_warrow            \
2946                -height $h                  \
2947                -anchor nw                  \
2948                -window $path.c.fg            \
2949                -tags   "leftarrow"
2950        } else {
2951            $path.c coords "leftarrow" $xl $y0
2952            $path.c itemconfigure "leftarrow" -width $_warrow -height $h
2953        }
2954        # Sven end
2955    } else {
2956        $path.c delete "leftarrow"
2957    }
2958
2959    if { $data(base) < $nbpages-1 &&
2960         $data(wpage) + [_get_x_page $path 0] + 6 > $w } {
2961        # Sven
2962        if { ![llength [$path.c find withtag "rightarrow"]] } {
2963            $path.c create window $xr $y0 \
2964                -width  $_warrow            \
2965                -height $h                  \
2966                -window $path.c.fd            \
2967                -anchor nw                  \
2968                -tags   "rightarrow"
2969        } else {
2970            $path.c coords "rightarrow" $xr $y0
2971            $path.c itemconfigure "rightarrow" -width $_warrow -height $h
2972        }
2973        # Sven end
2974    } else {
2975        $path.c delete "rightarrow"
2976    }
2977}
2978
2979proc NoteBook::_draw_area { path } {
2980    variable $path
2981    upvar 0  $path data
2982
2983    set w   [expr {[winfo width  $path] - 1}]
2984    set h   [expr {[winfo height $path] - 1}]
2985    set bd  [Widget::cget $path -borderwidth]
2986    if {$bd < 1} { set bd 1 }
2987    set x0  [expr {$bd - 1}]
2988
2989    set arcRadius [Widget::cget $path -arcradius]
2990
2991    # Sven
2992    set side [Widget::cget $path -side]
2993    if {"$side" == "bottom"} {
2994        set y0 0
2995        set y1 [expr {$h - $data(hpage)}]
2996        set yo $y1
2997    } else {
2998        set y0 $data(hpage)
2999        set y1 $h
3000        set yo [expr {$h-$y0}]
3001    }
3002    # Sven end
3003    set dbg $data(dbg)
3004    set sel $data(select)
3005    if {  $sel == "" } {
3006        set xd  [expr {$w/2}]
3007        set xf  $xd
3008        set lbg $data(dbg)
3009    } else {
3010        set xd [_get_x_page $path [lsearch -exact $data(pages) $data(select)]]
3011        set xf [expr {$xd + $data($sel,width) + $arcRadius + 1}]
3012        set lbg $data(lbg)
3013    }
3014
3015    # Sven
3016    if { [llength [$path.c find withtag rect]] == 0} {
3017        $path.c create line $xd $y0 $x0 $y0 $x0 $y1 \
3018            -tags "rect toprect1"
3019        $path.c create line $w $y0 $xf $y0 \
3020            -tags "rect toprect2"
3021        $path.c create line 1 $h $w $h $w $y0 \
3022            -tags "rect botrect"
3023    }
3024    if {"$side" == "bottom"} {
3025        $path.c coords "toprect1" $w $y0 $x0 $y0 $x0 $y1
3026        $path.c coords "toprect2" $x0 $y1 $xd $y1
3027        $path.c coords "botrect"  $xf $y1 $w $y1 $w $y0
3028        $path.c itemconfigure "toprect1" -fill $lbg -width $bd
3029        $path.c itemconfigure "toprect2" -fill $dbg -width $bd
3030        $path.c itemconfigure "botrect" -fill $dbg -width $bd
3031    } else {
3032        $path.c coords "toprect1" $xd $y0 $x0 $y0 $x0 $y1
3033        $path.c coords "toprect2" $w $y0 $xf $y0
3034        $path.c coords "botrect"  $x0 $h $w $h $w $y0
3035        $path.c itemconfigure "toprect1" -fill $lbg -width $bd
3036        $path.c itemconfigure "toprect2" -fill $lbg -width $bd
3037        $path.c itemconfigure "botrect" -fill $dbg -width $bd
3038    }
3039    $path.c raise "rect"
3040    # Sven end
3041
3042    if { $sel != "" } {
3043        # Sven
3044        if { [llength [$path.c find withtag "window"]] == 0 } {
3045            $path.c create window 2 [expr {$y0+1}] \
3046                -width  [expr {$w-3}]           \
3047                -height [expr {$yo-3}]          \
3048                -anchor nw                      \
3049                -tags   "window"                \
3050                -window $path.f$sel
3051        }
3052        $path.c coords "window" 2 [expr {$y0+1}]
3053        $path.c itemconfigure "window"    \
3054            -width  [expr {$w-3}]           \
3055            -height [expr {$yo-3}]          \
3056            -window $path.f$sel
3057        # Sven end
3058    } else {
3059        $path.c delete "window"
3060    }
3061}
3062
3063proc NoteBook::_resize { path } {
3064    variable $path
3065    upvar 0  $path data
3066
3067    if {!$data(realized)} {
3068	if { [set width  [Widget::cget $path -width]]  == 0 ||
3069	     [set height [Widget::cget $path -height]] == 0 } {
3070	    compute_size $path
3071	}
3072	set data(realized) 1
3073    }
3074
3075    NoteBook::_redraw $path
3076}
3077
3078proc NoteBook::_get_page_name { path {item current} {tagindex end-1} } {
3079    return [string range [lindex [$path.c gettags $item] $tagindex] 2 end]
3080}
3081# -----------------------------------------------------------------------------
3082#  scrollw.tcl -- part of Unifix BWidget Toolkit
3083# -----------------------------------------------------------------------------
3084
3085namespace eval ScrolledWindow {
3086    Widget::define ScrolledWindow scrollw
3087
3088    Widget::declare ScrolledWindow {
3089	{-background  TkResource ""   0 button}
3090	{-scrollbar   Enum	 both 0 {none both vertical horizontal}}
3091	{-auto	      Enum	 both 0 {none both vertical horizontal}}
3092	{-sides	      Enum	 se   0 {ne en nw wn se es sw ws}}
3093	{-size	      Int	 0    1 "%d >= 0"}
3094	{-ipad	      Int	 1    1 "%d >= 0"}
3095	{-managed     Boolean	 1    1}
3096	{-relief      TkResource flat 0 frame}
3097	{-borderwidth TkResource 0    0 frame}
3098	{-bg	      Synonym	 -background}
3099	{-bd	      Synonym	 -borderwidth}
3100    }
3101
3102    Widget::addmap ScrolledWindow "" :cmd {-relief {} -borderwidth {}}
3103}
3104
3105proc ScrolledWindow::create { path args } {
3106    Widget::init ScrolledWindow $path $args
3107
3108    Widget::getVariable $path data
3109
3110    set bg     [Widget::cget $path -background]
3111    set sbsize [Widget::cget $path -size]
3112    set sw     [eval [list frame $path \
3113			  -relief flat -borderwidth 0 -background $bg \
3114			  -highlightthickness 0 -takefocus 0] \
3115		    [Widget::subcget $path :cmd]]
3116
3117    scrollbar $path.hscroll \
3118	    -highlightthickness 0 -takefocus 0 \
3119	    -orient	 horiz	\
3120	    -relief	 sunken	\
3121	    -bg	 $bg
3122    scrollbar $path.vscroll \
3123	    -highlightthickness 0 -takefocus 0 \
3124	    -orient	 vert	\
3125	    -relief	 sunken	\
3126	    -bg	 $bg
3127
3128    set data(realized) 0
3129
3130    _setData $path \
3131	    [Widget::cget $path -scrollbar] \
3132	    [Widget::cget $path -auto] \
3133	    [Widget::cget $path -sides]
3134
3135    if {[Widget::cget $path -managed]} {
3136	set data(hsb,packed) $data(hsb,present)
3137	set data(vsb,packed) $data(vsb,present)
3138    } else {
3139	set data(hsb,packed) 0
3140	set data(vsb,packed) 0
3141    }
3142    if {$sbsize} {
3143	$path.vscroll configure -width $sbsize
3144	$path.hscroll configure -width $sbsize
3145    } else {
3146	set sbsize [$path.vscroll cget -width]
3147    }
3148    set data(ipad) [Widget::cget $path -ipad]
3149
3150    if {$data(hsb,packed)} {
3151	grid $path.hscroll -column 1 -row $data(hsb,row) \
3152		-sticky ew -ipady $data(ipad)
3153    }
3154    if {$data(vsb,packed)} {
3155	grid $path.vscroll -column $data(vsb,column) -row 1 \
3156		-sticky ns -ipadx $data(ipad)
3157    }
3158
3159    grid columnconfigure $path 1 -weight 1
3160    grid rowconfigure	 $path 1 -weight 1
3161
3162    bind $path <Configure> [list ScrolledWindow::_realize $path]
3163    bind $path <Destroy>   [list ScrolledWindow::_destroy $path]
3164
3165    return [Widget::create ScrolledWindow $path]
3166}
3167
3168proc ScrolledWindow::getframe { path } {
3169    return $path
3170}
3171
3172proc ScrolledWindow::setwidget { path widget } {
3173    Widget::getVariable $path data
3174
3175    if {[info exists data(widget)] && [winfo exists $data(widget)]
3176	&& ![string equal $data(widget) $widget]} {
3177	grid remove $data(widget)
3178	$data(widget) configure -xscrollcommand "" -yscrollcommand ""
3179    }
3180    set data(widget) $widget
3181    grid $widget -in $path -row 1 -column 1 -sticky news
3182
3183    $path.hscroll configure -command [list $widget xview]
3184    $path.vscroll configure -command [list $widget yview]
3185    $widget configure \
3186	    -xscrollcommand [list ScrolledWindow::_set_hscroll $path] \
3187	    -yscrollcommand [list ScrolledWindow::_set_vscroll $path]
3188}
3189
3190proc ScrolledWindow::configure { path args } {
3191    Widget::getVariable $path data
3192
3193    set res [Widget::configure $path $args]
3194    if { [Widget::hasChanged $path -background bg] } {
3195	$path configure -background $bg
3196	catch {$path.hscroll configure -background $bg}
3197	catch {$path.vscroll configure -background $bg}
3198    }
3199
3200    if {[Widget::hasChanged $path -scrollbar scrollbar] | \
3201	    [Widget::hasChanged $path -auto	 auto]	| \
3202	    [Widget::hasChanged $path -sides	 sides]} {
3203	_setData $path $scrollbar $auto $sides
3204	foreach {vmin vmax} [$path.hscroll get] { break }
3205	set data(hsb,packed) [expr {$data(hsb,present) && \
3206		(!$data(hsb,auto) || ($vmin != 0 || $vmax != 1))}]
3207	foreach {vmin vmax} [$path.vscroll get] { break }
3208	set data(vsb,packed) [expr {$data(vsb,present) && \
3209		(!$data(vsb,auto) || ($vmin != 0 || $vmax != 1))}]
3210
3211	set data(ipad) [Widget::cget $path -ipad]
3212
3213	if {$data(hsb,packed)} {
3214	    grid $path.hscroll -column 1 -row $data(hsb,row) \
3215		-sticky ew -ipady $data(ipad)
3216	} else {
3217	    if {![info exists data(hlock)]} {
3218		set data(hsb,packed) 0
3219		grid remove $path.hscroll
3220	    }
3221	}
3222	if {$data(vsb,packed)} {
3223	    grid $path.vscroll -column $data(vsb,column) -row 1 \
3224		-sticky ns -ipadx $data(ipad)
3225	} else {
3226	    if {![info exists data(hlock)]} {
3227		set data(vsb,packed) 0
3228		grid remove $path.vscroll
3229	    }
3230	}
3231    }
3232    return $res
3233}
3234
3235proc ScrolledWindow::cget { path option } {
3236    return [Widget::cget $path $option]
3237}
3238
3239proc ScrolledWindow::_set_hscroll { path vmin vmax } {
3240    Widget::getVariable $path data
3241
3242    if {$data(realized) && $data(hsb,present)} {
3243	if {$data(hsb,auto) && ![info exists data(hlock)]} {
3244	    if {$data(hsb,packed) && $vmin == 0 && $vmax == 1} {
3245		set data(hsb,packed) 0
3246		grid remove $path.hscroll
3247		set data(hlock) 1
3248		update idletasks
3249		unset data(hlock)
3250	    } elseif {!$data(hsb,packed) && ($vmin != 0 || $vmax != 1)} {
3251		set data(hsb,packed) 1
3252		grid $path.hscroll -column 1 -row $data(hsb,row) \
3253			-sticky ew -ipady $data(ipad)
3254		set data(hlock) 1
3255		update idletasks
3256		unset data(hlock)
3257	    }
3258	}
3259	$path.hscroll set $vmin $vmax
3260    }
3261}
3262
3263proc ScrolledWindow::_set_vscroll { path vmin vmax } {
3264    Widget::getVariable $path data
3265
3266    if {$data(realized) && $data(vsb,present)} {
3267	if {$data(vsb,auto) && ![info exists data(vlock)]} {
3268	    if {$data(vsb,packed) && $vmin == 0 && $vmax == 1} {
3269		set data(vsb,packed) 0
3270		grid remove $path.vscroll
3271		set data(vlock) 1
3272		update idletasks
3273		unset data(vlock)
3274	    } elseif {!$data(vsb,packed) && ($vmin != 0 || $vmax != 1) } {
3275		set data(vsb,packed) 1
3276		grid $path.vscroll -column $data(vsb,column) -row 1 \
3277			-sticky ns -ipadx $data(ipad)
3278		set data(vlock) 1
3279		update idletasks
3280		unset data(vlock)
3281	    }
3282	}
3283	$path.vscroll set $vmin $vmax
3284    }
3285}
3286
3287proc ScrolledWindow::_setData {path scrollbar auto sides} {
3288    Widget::getVariable $path data
3289
3290    set sb    [lsearch {none horizontal vertical both} $scrollbar]
3291    set auto  [lsearch {none horizontal vertical both} $auto]
3292
3293    set data(hsb,present)  [expr {($sb & 1) != 0}]
3294    set data(hsb,auto)	   [expr {($auto & 1) != 0}]
3295    set data(hsb,row)	   [expr {[string match *n* $sides] ? 0 : 2}]
3296
3297    set data(vsb,present)  [expr {($sb & 2) != 0}]
3298    set data(vsb,auto)	   [expr {($auto & 2) != 0}]
3299    set data(vsb,column)   [expr {[string match *w* $sides] ? 0 : 2}]
3300}
3301
3302proc ScrolledWindow::_realize { path } {
3303    Widget::getVariable $path data
3304
3305    bind $path <Configure> {}
3306    set data(realized) 1
3307}
3308
3309proc ScrolledWindow::_destroy { path } {
3310    Widget::destroy $path
3311}
3312
3313############ end of BWidget code ##############
3314############ iSpin GUI specific code: #########
3315
3316set Fname ""
3317set Sname "ispin_session"
3318set lno 1
3319set Curp Mp
3320
3321set s_typ 0
3322set seed 123
3323set skipstep 0
3324set ubstep 10000
3325set l_typ 0
3326
3327set stop 0
3328set step 0
3329set maxn 0
3330set curn 0
3331set lno 0
3332set cnt 1
3333set msc_full 0
3334set negate_ltl 0
3335set var_vals 1
3336
3337set vo 0	;# verification output
3338set vr 0	;# verification reference
3339
3340set msc_x 75
3341set msc_y 20
3342set msc_w 75
3343set msc_h 20
3344set msc_max_x $msc_x
3345set msc_delay 25	;# milliseconds update delay
3346set msc_max_w 20
3347
3348set Varnm() 0
3349set VarStep() 0
3350set Levels() 0
3351set LineNo() 0
3352set MSC_Y() 0
3353set LineTouched() 0
3354
3355set sym_pan ""
3356set note_pan ""
3357set nvr_pan ""
3358set log_pan ""
3359
3360set bet(0)	"Physical Memory Available (in Mbytes): "
3361set ival(0)	1024
3362set expl(0)	"explain"
3363
3364set bet(1)	"Estimated State Space Size (states x 10^3): "
3365set ival(1)	1000
3366set expl(1)	"explain"
3367
3368set bet(2)	"Maximum Search Depth (steps): "
3369set ival(2)	10000
3370set expl(2)	"explain"
3371
3372set bet(3)	"Nr of hash-functions in Bitstate mode: "
3373set ival(3)	3
3374set expl(3)	"explain"
3375
3376set bet(4)	"Size for Minimized Automaton"
3377set ival(4)	100
3378set expl(4)	"explain"
3379
3380set bet(5)	"Extra Verifier Generation Options: "
3381set ival(5)	""
3382set expl(5)	"explain"
3383
3384set bet(6)	"Extra Compile-Time Directives: "
3385set ival(6)	"-O2"
3386set expl(6)	"explain"
3387
3388set bet(7)	"Extra Run-Time Options: "
3389set ival(7)	""
3390set expl(7)	"explain"
3391
3392set estop 0
3393set s_mode 0
3394set po_mode 1
3395set bf_mode 0
3396set ma_mode 0
3397set cc_mode 0
3398set p_mode 0
3399set c_mode 0
3400set u_mode 1
3401set a_mode 1
3402set x_mode 0
3403set e_mode 1
3404set q_mode 0
3405set f_mode 0
3406set bc_mode 0
3407set it_mode 0
3408set sv_mode 0
3409set vpanel 0
3410set spanel 0
3411
3412set pat ""	;# search pattern
3413
3414set swarm_p(0) "minimum nr of hash functions:"
3415set swarm_i(0) "1"
3416set swarm_p(1) "maximum nr of hash functions:"
3417set swarm_i(1) "5"
3418set swarm_p(2) "minimum search depth:"
3419set swarm_i(2) "100"
3420set swarm_p(3) "maximum search depth:"
3421set swarm_i(3) "10000"
3422set swarm_p(4) "number of local cpu-cores"
3423set swarm_i(4) "4"
3424set swarm_p(5) "list of remote_cpu_name:ncores"
3425set swarm_i(5) ""
3426set swarm_p(6) "maximum memory per run (suffix: M or G)"
3427set swarm_i(6) "512M"
3428set swarm_p(7) "maximum total runtime for swarm (suffix: s, m, h, d)"
3429set swarm_i(7) "60m"
3430
3431set swarm_p(8) "hash-factor"
3432set swarm_i(8) "1.5"
3433set swarm_p(9) "state-vector size in bytes"
3434set swarm_i(9) "512"
3435set swarm_p(10) "exploration speed in states/sec"
3436set swarm_i(10) "250000"
3437
3438set so 0	;# swarm cfg output
3439set sr 0	;# swarm run output
3440
3441set o_v 0
3442set o_y 30
3443
3444proc add_frame {fn t} {
3445	global TBG TFG
3446
3447	frame $fn -bg $TBG
3448	label $fn.lbl -text "$t" -bg $TBG -fg $TFG
3449	entry $fn.ent -relief sunken -width 10
3450
3451	pack $fn -side top -fill x -expand yes
3452	pack $fn.lbl -side left -fill x -expand no
3453	pack $fn.ent -side right -fill x -expand no
3454
3455	bind $fn.ent <Return> { run_sim }
3456}
3457
3458proc do_find {} {
3459	global twin pat
3460
3461	$twin tag remove hilite 0.0 end
3462	forAllMatches $twin $pat
3463}
3464
3465proc model_panel {t} {
3466	global clog twin fg CBG CFG HV0 HV1 TBG TFG MFG NFG NBG pat ScrollBarSize Fname
3467global xzx
3468	frame $t.buttons -bg $CBG
3469	button $t.buttons.open -text "Open..." -command "open_spec 1" \
3470		-bg $NBG -fg white -font $HV0 \
3471		-activebackground $NFG -activeforeground $NBG
3472	button $t.buttons.ref -text "ReOpen" -command "open_spec 0" \
3473		-bg $NBG -fg white -font $HV0 \
3474		-activebackground $NFG -activeforeground $NBG
3475	button $t.buttons.save -text "Save" -command "save_spec 0" \
3476		-bg $NBG -fg white -font $HV0 \
3477		-activebackground $NFG -activeforeground $NBG
3478	button $t.buttons.saveas -text "Save As..." -command "save_spec 1" \
3479		-bg $NBG -fg white -font $HV0 \
3480		-activebackground $NFG -activeforeground $NBG
3481	button $t.buttons.syntax -text "Syntax Check" -command "runsyntax 0" \
3482		-bg $NBG -fg $NFG -font $HV0 \
3483		-activebackground $NFG -activeforeground $NBG
3484	button $t.buttons.slice -text "Redundancy Check" -command "runsyntax 1" \
3485		-bg $NBG -fg $NFG -font $HV0 \
3486		-activebackground $NFG -activeforeground $NBG
3487	button $t.buttons.symb -text "Symbol Table" -command "symbol_table" \
3488		-bg $NBG -fg $NFG -font $HV0 \
3489		-activebackground $NFG -activeforeground $NBG
3490	button $t.buttons.fnd1 -text "Find:" \
3491		-command "do_find" \
3492		-bg $NBG -fg white -font $HV0 \
3493		-activebackground $NFG -activeforeground $NBG
3494	entry $t.buttons.fnd2 -width 24 -textvariable pat -bg ivory \
3495		-relief sunken -background $TBG -foreground $TFG
3496	bind  $t.buttons.fnd2 <Return> { do_find }
3497
3498	pack $t.buttons -side top -fill x -expand no
3499
3500	pack	$t.buttons.open $t.buttons.ref $t.buttons.save \
3501		$t.buttons.saveas \
3502		$t.buttons.syntax $t.buttons.slice \
3503		$t.buttons.symb \
3504		-side left -fill x -expand no
3505
3506	pack $t.buttons.fnd1 $t.buttons.fnd2 \
3507		-side left -fill x -expand no
3508
3509	set pw  [PanedWindow $t.pw -side left -activator button ]
3510
3511	set p2  [$pw add -minsize 100]
3512	set p1  [$pw add -minsize 20]
3513
3514        set sw11   [ScrolledWindow $p1.sw -size $ScrollBarSize]
3515        set clog   [text $sw11.lb -height 15 -width 100 -highlightthickness 3 -bg $CBG -fg $CFG -font $HV1]
3516	$sw11 setwidget $clog
3517	pack $sw11 -fill both -expand yes
3518###
3519	set xx [PanedWindow $p2.wide -side top -activator button ]
3520	set q0 [$xx add -minsize 10]
3521	set q1 [$xx add -minsize 10]
3522
3523	set sw22   [ScrolledWindow $q0.wide -size $ScrollBarSize]
3524	set twin   [text $sw22.lb -undo 1 -height 30 -highlightthickness 0 -font $HV1]
3525	$sw22 setwidget $twin
3526
3527	pack $sw22 -side left -fill both -expand yes
3528
3529	$twin insert end "model source $Fname"
3530	$twin edit modified false
3531
3532	global scrollxregion scrollyregion
3533
3534	set cv [ScrolledWindow $q1.wide -size $ScrollBarSize]
3535	set fg [canvas $cv.right -relief raised \
3536		-background $NBG -scrollregion "0 0 $scrollxregion $scrollyregion" ]
3537set xzx $fg
3538	$cv setwidget $fg
3539
3540	frame $q1.ctl -bg $NBG
3541
3542	button $q1.ctl.mkg -text "Automata View" -command "mk_graphs" \
3543		-bg $NBG -fg $NFG -font $HV0 \
3544		-activebackground $NFG -activeforeground $NBG
3545	button $q1.ctl.plus  -text "zoom in" -command "$fg scale all 0 0 1.1 1.1" -width 10 \
3546		-bg $NBG -fg $NFG -font $HV0 \
3547		-activebackground $NFG -activeforeground $NBG
3548	button $q1.ctl.minus -text "zoom out" -command "$fg scale all 0 0 0.9 0.9" -width 10 \
3549		-bg $NBG -fg $NFG -font $HV0 \
3550		-activebackground $NFG -activeforeground $NBG
3551
3552	pack $q1.ctl $q1.ctl.mkg   -side left  -fill x -expand no
3553	pack $q1.ctl $q1.ctl.minus -side right -fill x -expand no
3554	pack $q1.ctl $q1.ctl.plus  -side right -fill x -expand no
3555	pack $q1 $q1.ctl -side top
3556
3557	pack $cv -side right -fill both -expand yes
3558	pack $xx -fill both -expand yes
3559	pack $pw -fill both -expand yes
3560
3561	bind  $twin <KeyRelease> {
3562		if {"%K" == "Return"} {
3563			$twin insert insert "[$twin index insert]	"
3564			$twin edit modified true
3565	}	}
3566
3567	bind $fg <2> "$fg scan mark %x %y"
3568	bind $fg <B2-Motion> "$fg scan dragto %x %y"
3569}
3570
3571proc checked_exit {} {
3572	global twin
3573
3574	if {[$twin edit modified]} {
3575		set answer [tk_messageBox -icon question -type yesno \
3576		 -message "There are unsaved changes. Really Quit?" ]
3577		switch -- $answer {
3578		yes { }
3579		no  { return }
3580		}
3581	}
3582	destroy .
3583	exit
3584}
3585
3586proc mk_pan { t GC CC } {
3587	global vo RM
3588
3589	set errmsg ""
3590	$vo insert end $GC\n; update
3591	set fd -1
3592	catch {set fd [open "|$GC" r]} errmsg
3593	if {$fd == -1} {
3594		$vo delete 0.0 end
3595		$vo insert end "error:  $errmsg\n"
3596			$vo yview end
3597		return
3598	} else {
3599		while {[gets $fd line] > -1} {
3600			$vo insert end "$line\n"
3601			$vo yview end
3602			update
3603		}
3604		catch " close $fd "
3605	}
3606
3607	$vo insert end $CC\n; update
3608
3609	catch "eval exec $CC >& pan.tmp"
3610
3611	set fd -1
3612	catch {set fd [open "pan.tmp" r]} errmsg
3613	if {$fd == -1} {
3614		$vo delete 0.0 end
3615		$vo insert end "$errmsg\n"
3616		$vo yview end
3617	} else {
3618		while {[gets $fd line] > -1} {
3619			$vo insert end "$line\n"
3620			$vo yview end
3621			update
3622		}
3623		catch " close $fd "
3624	}
3625	catch { eval exec "$RM pan.tmp" }
3626	update
3627}
3628
3629proc run_pan { t VC d } {
3630	global vr vo stop KILL
3631
3632	if {[auto_execok "./pan"] == ""} {
3633		return
3634	}
3635
3636	$vo insert end $VC\n; update
3637	set fd -1
3638
3639	set pid [eval exec $VC >& run.tmp &]
3640	$vo insert end "Pid: $pid\n"
3641	$vo yview end
3642
3643	catch {set fd [open "run.tmp" r]} errmsg
3644	if {$fd == -1} {
3645		$vo insert end "error: $errmsg\n"
3646		$vo yview end
3647		return
3648	}
3649	set stop 0
3650	set pname "--"
3651	if {$d == 1} {
3652		$vo delete 0.0 end
3653		$vo insert end "proc\tfrom\ttrans\tto\tsrc\tstmnt\n"
3654		$vo insert end "name\tstate\tid\tstate\n"
3655	}
3656	set no_errors 0
3657	set seen_ln 0
3658	while {$stop == 0} {
3659		if {[gets $fd line] == -1} {
3660			after 10
3661			$vo yview end
3662			update
3663			if {$seen_ln == 0} {
3664				# courtesy martin vuille
3665				after 10
3666				catch { close $fd }
3667				set fd [open "run.tmp" r]
3668			}
3669			continue
3670		}
3671		set seen_ln 1
3672		if {[string first "No tty allocated" $line] >= 0} {
3673			continue
3674		}
3675		if {[string first "Valid Options are:" $line] >= 0} {
3676			while {[gets $fd line] != -1} {
3677				$vo insert end "$line\n"
3678				update
3679			}
3680			set stop 2
3681		}
3682
3683		if {[string first "pan: elapsed" $line] >= 0} {
3684			set stop 2
3685		}
3686
3687		if {$d == 0} {
3688			$vo insert end "$line\n"
3689			$vo yview end
3690			update
3691			if {[string first "State-vector " $line] >= 0} {
3692				if {[string first "errors: 0" $line] >= 0} {
3693					set no_errors 1
3694			}	}
3695			continue
3696		}
3697		if {[string first "proctype" $line] == 0} {
3698			set pname [string range $line 9 end]
3699			$vo insert end "\n"
3700			$vo yview end
3701			continue
3702		}
3703		if {[string first "Transition" $line] >= 0 \
3704		||  [string first "Source-State" $line] >= 0 \
3705		||  [string first "Note:" $line] >= 0 \
3706		||  [string first "pan:" $line] >= 0} {
3707			continue
3708		}
3709		# format:
3710		# state  15 -(tr  18)-> state  31  [id  14 tp   5] [----L] leader:36 => out!first,number
3711
3712		regexp {[A-Za-z0-9_\.]+:[0-9]+} $line matched	;# file:line
3713
3714		set pre [string first "\[" $line]
3715		set frst [string range $line 0 $pre]
3716		set lst  [string range $line $pre end]
3717		set arr  [string first " => " $lst]; incr arr 4
3718		set stmnt [string range $lst $arr end]
3719		if {[scan $line "\tstate %d -(tr %d)-> state %d \[id %d tp %d\]" \
3720			f1 f2 f3 f4 f5] == 5} {
3721			$vo insert end "$pname\t$f1\t\[$f2\]\t$f3\t$matched\t$stmnt\n"
3722		} else {
3723			$vo insert end "$line\n"
3724	}	}
3725
3726	if {$stop == 1} {
3727		catch "eval exec $KILL $pid"
3728		$vo insert end "stopped\n"
3729		while {[gets $fd line] != -1} {
3730			$vo insert end "$line\n"
3731			$vo yview end
3732			update
3733	}	}
3734	catch " close $fd " errmsg
3735	if {$errmsg != "" && [string first "No tty allocated" $errmsg] < 0} {
3736		$vo insert end "$errmsg\n"
3737	}
3738	$vo yview end
3739
3740	if {$no_errors == 0} {
3741		$vo insert end "To replay the error-trail, goto Simulate/Replay and select \"Run\"\n"
3742	} else {
3743		$vo insert end "No errors found -- did you verify all claims?\n"
3744	}
3745
3746	bind_lines $vo $vr
3747
3748	update
3749}
3750
3751proc log { n } {
3752	set m 1
3753	set cnt 0
3754	while {$m<$n} {
3755		set m [expr $m*2]
3756		incr cnt
3757	}
3758	return $cnt
3759}
3760
3761proc run_tbl { t } {
3762	global Fname CC
3763
3764	if {$Fname == ""} { return }
3765
3766	mk_pan $t "spin -a [$t.top.right.row5.ent get] $Fname" "$CC -w -o pan pan.c"
3767	run_pan $t "./pan -d" 1
3768	cleanup
3769}
3770
3771proc has_label {s dargs} {
3772	global vr SPIN Fname
3773
3774	set ST "$SPIN -d $dargs $Fname"
3775	set result 0
3776
3777	catch {set fd [open "|$ST" r]} errmsg
3778	if {$fd == -1} {
3779		$vr insert end "$errmsg\n"
3780		$vr yview end
3781		update
3782	} else {
3783		while {[gets $fd line] > -1} {
3784			if {[string first "label	$s" $line] >= 0} {
3785				set result 1
3786				break
3787		}	}
3788		catch " close $fd "
3789	}
3790	return $result
3791}
3792
3793proc check_sanity {gargs} {
3794	global p_mode vo
3795
3796	if {[has_label "accept" $gargs] == 1} {
3797		if {$p_mode != 2} {
3798			$vo insert end "warning: model has accept states\n"
3799		}
3800	} else {
3801		if {$p_mode == 2} {
3802			$vo insert end "error: model has no accept states\n"
3803			return 0
3804	}	}
3805	if {[has_label "progress" $gargs] == 1} {
3806		if {$p_mode != 1} {
3807			$vo insert end "warning: model has progress states\n"
3808		}
3809	} else {
3810		if {$p_mode == 1} {
3811			$vo insert end "error: model has no progress states\n"
3812			return 0
3813	}	}
3814	$vo yview end
3815
3816	return 1
3817}
3818
3819proc run_ver { t } {
3820	global Fname q_mode f_mode bc_mode it_mode sv_mode
3821	global bet ival expl estop s_mode po_mode bf_mode e_mode
3822	global ma_mode cc_mode p_mode c_mode u_mode a_mode x_mode
3823	global nvr_pan sym_pan SPIN CC vo peg vranges LTL_Panel
3824	global V_Panel_1 V_Panel_3
3825
3826	set nc_nm ""
3827	set match_start ""
3828
3829	set gargs "-a"
3830		if {$q_mode}   { set gargs "$gargs -m" }
3831		if {$peg == 1} { set gargs "$gargs -o3" }
3832
3833		if {$c_mode == 2} {
3834			catch { exec $SPIN -e $Fname > "never_claim.tmp" } errmsg
3835			if {$errmsg != ""} {
3836				$vo insert end $errmsg\n
3837				$vo yview end
3838				return
3839			}
3840			set nc_nm "Product"
3841			set gargs "$gargs -N never_claim.tmp"
3842			if {[check_sanity $gargs] == 0} {
3843				$vo yview end
3844				return
3845		}	}
3846
3847		if {$c_mode == 1} {
3848			if {$LTL_Panel} {
3849				if [catch { set fd [open "never_claim.tmp" w] } errmsg] {
3850					$vo insert end $errmsg\n
3851					$vo yview end
3852					return
3853				}
3854				puts $fd [$sym_pan get 0.0 end]
3855				puts $fd [$nvr_pan get 0.0 end]
3856
3857				regexp {never .*\{} [$nvr_pan get 0.0 end] match_start
3858				if {$match_start == ""} {
3859					$vo insert end "error: cannot find never claim\n"
3860					$vo yview end
3861					return
3862				}
3863				set match_end [string first " \{" $match_start]
3864				if {$match_end > 0} {
3865					incr match_end -1
3866				}
3867				set nc_nm [string range $match_start 6 $match_end]
3868				# $vo insert end "\nusing claim: \'$nc_nm\'\n\n"
3869				# $vo yview end
3870
3871				catch "close $fd"
3872				set gargs "$gargs -N never_claim.tmp"
3873				if {[check_sanity $gargs] == 0} {
3874					$vo yview end
3875					return
3876				}
3877				$vo insert end "wrote never_claim.tmp\n"
3878			} else {
3879				set nc_nm [$t.top.fourth.rowA.nr get]
3880			}
3881		}
3882
3883	$vo yview end
3884	update
3885
3886	if {$V_Panel_3} {
3887		set cargs "-DMEMLIM=[$t.top.right.row0.ent get] [$t.top.right.row6.ent get]"
3888	} else {
3889		set cargs "-DMEMLIM=$ival(0) $ival(6)"
3890	}
3891		if {$s_mode == 1}  { set cargs "$cargs -DBITSTATE" }
3892		if {$s_mode == 2}  { set cargs "$cargs -DHC4" }
3893
3894		if {$V_Panel_3} {
3895		if {$ma_mode == 1} { set cargs "$cargs -DMA=[$t.top.right.row4.ent get]" }
3896		if {$ma_mode == 1} { set cargs "$cargs -DMA=$ival(4)" }
3897		} else {
3898		}
3899		if {$bf_mode == 1} { set cargs "$cargs -DBFS" }
3900		if {$x_mode == 0}  { set cargs "$cargs -DXUSAFE" }
3901		if {$p_mode == 0}  { set cargs "$cargs -DSAFETY" }
3902		if {$p_mode == 1}  { set cargs "$cargs -DNP" }
3903		if {$c_mode == 0}  { set cargs "$cargs -DNOCLAIM" }
3904		if {$cc_mode == 1} { set cargs "$cargs -DCOLLAPSE" }
3905		if {$bc_mode == 1} { set cargs "$cargs -DBCS" }
3906		if {$it_mode == 1} { set cargs "$cargs -DREACH" }
3907		if {$po_mode == 0} { set cargs "$cargs -DNOREDUCE" }
3908		if {$peg == 1}     { set cargs "$cargs -DPEG" }
3909		if {$vranges == 1} { set cargs "$cargs -DVAR_RANGES" }
3910
3911		if {$V_Panel_3} {
3912			set vargs "-m[$t.top.right.row2.ent get] [$t.top.right.row7.ent get]"
3913			if {$s_mode == 1} { set vargs "$vargs -k[$t.top.right.row3.ent get]" }
3914		} else {
3915			set vargs "-m$ival(2) $ival(7)"
3916			if {$s_mode == 1} { set vargs "$vargs -k$ival(3)" }
3917		}
3918		if {$e_mode == 0} { set vargs "$vargs -E" }
3919		if {$a_mode == 0} { set vargs "$vargs -A" }
3920		if {$p_mode == 1} { set vargs "$vargs -l" }
3921		if {$p_mode == 2} { set vargs "$vargs -a" }
3922		if {$f_mode == 1} { set vargs "$vargs -f" }
3923		if {$u_mode == 0} { set vargs "$vargs -n" }
3924		if {$it_mode == 1} { set vargs "$vargs -i" }
3925		if {$estop == 1}  { set vargs "$vargs -c0" }
3926
3927		if {$V_Panel_1} {
3928		if {$estop == 0}  { set vargs "$vargs -c[$t.top.middle.row1.nr get]" }
3929		}
3930
3931		if {$sv_mode == 1} { set vargs "$vargs -e" }
3932		if {$s_mode == 1} {
3933			if {$V_Panel_3} {
3934				set vargs "$vargs -w[expr 10+[log [$t.top.right.row1.ent get]]]"
3935			} else {
3936				set vargs "$vargs -w[expr 10+[log $ival(1)]]"
3937		}	}
3938		if {$bc_mode == 1} {
3939			set vargs "$vargs -L[$t.top.third.rowB.ent get]"
3940		}
3941		if {$nc_nm != ""} { set vargs "$vargs -N $nc_nm" }
3942
3943	if {$V_Panel_3} {
3944		set GC "$SPIN $gargs [$t.top.right.row5.ent get] $Fname"
3945	} else {
3946		set GC "$SPIN $gargs $ival(5) $Fname"
3947	}
3948	set CL "$CC $cargs -w -o pan pan.c"
3949	set VC "./pan $vargs"
3950
3951	$vo yview end
3952	update
3953
3954	mk_pan $t $GC $CL
3955	run_pan $t $VC 0
3956	cleanup
3957}
3958
3959proc stop_ver { t } {
3960	global stop
3961	set stop 1
3962}
3963
3964proc useful_info { sr cmd } {
3965
3966	catch { set fd [open "|$cmd" r] } errmsg
3967	if {$fd == -1} {
3968		$sr insert end "error: $errmsg"
3969		return
3970	}
3971	while {[gets $fd line] > -1} {
3972		$sr insert end "$line\n"
3973		$sr yview end
3974		update
3975	}
3976	catch "close $fd" errmsg
3977	$sr insert end "$errmsg\n"
3978	$sr yview end
3979	update
3980}
3981
3982proc swarm_gen { t } {
3983	global so sr Fname SWARM
3984
3985	if {[auto_execok $SWARM] == ""} {
3986		add_log "no swarm command is installed on this system" 0
3987		add_log "it is available from: http://spinroot.com/swarm/" 0
3988		tk_messageBox -icon info -message "No executable $SWARM found..."
3989		return
3990	}
3991
3992	if [catch {set fd [open "swarm_cfg.tmp" w]} errmsg] {
3993		$so insert end "error: cannot write swarm_cfg.tmp\n"
3994		return
3995	}
3996
3997	puts $fd "## Swarm Version 3.0 -- 16 August 2010"
3998	puts $fd "#"
3999	puts $fd "# range"
4000	puts $fd "k	[$t.top.left.row0.e0 get]	[$t.top.left.row1.e0 get]\n"
4001
4002	puts $fd "# limits"
4003	puts $fd "d	[$t.top.left.row3.e0 get]"	;# later also add min: [$t.top.left.row2.e0 get]
4004	puts $fd "cpus	[$t.top.left.row4.e0 get]	[$t.top.left.row5.e0 get]"
4005
4006	puts $fd "memory	[$t.top.left.row6.e0 get]"
4007	puts $fd "time	[$t.top.left.row7.e0 get]"
4008	puts $fd "hash	[$t.top.middle.row8.e1 get]"
4009	puts $fd "vector	[$t.top.middle.row9.e1 get]"
4010	puts $fd "speed	[$t.top.middle.row10.e1 get]"
4011	puts $fd "file	$Fname\n"
4012
4013	puts $fd "# compilation options"
4014	puts $fd "[$t.top.right.row0 get 0.0 end]"
4015	puts $fd "# runtime options (one line only)"
4016	puts $fd "[$t.top.middle.row12.e1 get]\n"
4017	puts $fd "# spin options other than -a (one line only)"
4018	puts $fd "[$t.top.middle.row11.e1 get]\n"
4019	catch "close $fd" errmsg
4020
4021	$so insert end "generated configuration file\n"
4022
4023	catch { set fd [open "|$SWARM swarm_cfg.tmp" r] } errmsg
4024	if {$fd == -1} {
4025		$so insert end "error: $errmsg"
4026		return
4027	}
4028	while {[gets $fd line] > -1} {
4029		$so insert end "$line\n"
4030		$so yview end
4031		update
4032	}
4033	catch "close $fd" errmsg
4034	$so insert end "done:: $errmsg \n"
4035	$so yview end
4036	update
4037
4038	$so insert end "----Running----\n"
4039	$so yview end
4040	update
4041
4042	set nxn [string first "." $Fname]
4043	if {$nxn > 0} {
4044		incr nxn -1
4045		set sFname [string range $Fname 0 $nxn]
4046	} else {
4047		set sFname $Fname
4048	}
4049## untested:
4050	if {[string first "C:" $sFname] >= 0 || [string first "/" $sFname] == 0} {
4051		catch { set fd [open "|sh $sFname*.swarm" r] } errmsg
4052	} else {
4053		catch { set fd [open "|sh ./$sFname*.swarm" r] } errmsg
4054	}
4055	if {$fd == -1} {
4056		$so insert end "error: $errmsg"
4057		return
4058	}
4059	while {[gets $fd line] > -1} {
4060		$so insert end "$line\n"
4061		$so yview end
4062		update
4063	}
4064	catch "close $fd" errmsg
4065	$so insert end "run completed\n$errmsg\n"
4066	$so yview end
4067	update
4068
4069	useful_info $sr "grep -e errors: script*.out"
4070	useful_info $sr "ls -l *.trail"
4071}
4072
4073proc swarm_clean { } {
4074	global Fname so RM
4075
4076	cleanup
4077	catch { eval exec $RM swarm_cfg.tmp $Fname.swarm script* } err
4078	$so insert end $err\n
4079	$so yview end
4080}
4081
4082proc swarm_panel { t } {
4083	global swarm_p swarm_i CBG CFG TBG TFG NBG NFG HV0 HV1
4084	global SWARM so sr ScrollBarSize spanel
4085
4086	set spanel $t
4087
4088	frame $t.top -bg $TBG
4089	pack $t.top -side top -fill both -expand no
4090
4091	frame $t.top.left -bg $TBG
4092	frame $t.top.middle -bg $TBG
4093	frame $t.top.right -bg $TBG
4094	pack $t.top.left $t.top.middle $t.top.right -side left -fill both -expand no
4095
4096	set p1 $t.top.left
4097	label $p1.limits -text "Search Constraints" -relief sunken -bg $TBG -fg $TFG
4098	pack $p1.limits -side top -fill x -expand no
4099
4100	for {set i 0} {$i < 8} {incr i} {
4101		frame $p1.row$i -bg $TBG
4102			label $p1.row$i.k0 -text "$swarm_p($i)" -bg $TBG -fg $TFG
4103			entry $p1.row$i.e0 -relief sunken
4104			$p1.row$i.e0 insert end "$swarm_i($i)"
4105
4106		pack $p1.row$i.k0 -side left -fill x -expand no
4107		pack $p1.row$i.e0 -side right -fill x -expand no
4108		pack $p1.row$i -side top -fill x -expand no
4109	}
4110
4111	set p2 $t.top.middle
4112	label $p2.limits -text "Estimates (Fine Tuning)" -relief sunken -bg $TBG -fg $TFG
4113	pack $p2.limits -side top -fill x -expand no
4114
4115	for {set i 8} {$i < 11} {incr i} {
4116		frame $p2.row$i -bg $TBG
4117			label $p2.row$i.k1 -text "$swarm_p($i)" -bg $TBG -fg $TFG
4118			entry $p2.row$i.e1 -relief sunken
4119			$p2.row$i.e1 insert end "$swarm_i($i)"
4120		pack $p2.row$i.k1 -side left -fill x -expand no
4121		pack $p2.row$i.e1 -side right -fill x -expand no
4122		pack $p2.row$i -side top -fill x -expand no
4123	}
4124
4125	label $p2.other -text "Model Generation" -relief sunken -bg $TBG -fg $TFG
4126	pack $p2.other -side top -fill x -expand no
4127	frame $p2.row11 -bg $TBG
4128		label $p2.row11.k1 -text "extra spin args" -bg $TBG -fg $TFG
4129		entry $p2.row11.e1 -relief sunken
4130		pack $p2.row11.k1 -side left -fill x -expand no
4131		pack $p2.row11.e1 -side right -fill x -expand no
4132		pack $p2.row11 -side top -fill x -expand no
4133	frame $p2.row12 -bg $TBG
4134		label $p2.row12.k1 -text "extra pan args" -bg $TBG -fg $TFG
4135		entry $p2.row12.e1 -relief sunken
4136		$p2.row12.e1 insert end "-c1 -x -n"
4137		pack $p2.row12.k1 -side left -fill x -expand no
4138		pack $p2.row12.e1 -side right -fill x -expand no
4139		pack $p2.row12 -side top -fill x -expand no
4140
4141	frame $p2.buttons -bg $TBG
4142	button $p2.buttons.run -text "Run" -command "swarm_gen $t" \
4143		-bg $NBG -fg $NFG -font $HV0 \
4144		-activebackground $NFG -activeforeground $NBG
4145
4146	button $p2.buttons.cln -text "Cleanup tmp files" -command "swarm_clean" \
4147		-bg $NBG -fg $NFG -font $HV0 \
4148		-activebackground $NFG -activeforeground $NBG
4149
4150	pack $p2.buttons.cln -side right -fill x -expand no
4151	pack $p2.buttons.run -side right -fill x -expand no
4152	pack $p2.buttons -side bottom -fill x -expand no
4153
4154
4155	set p3 $t.top.right
4156	label $p3.limits -text "Compilation Options (any number, one per line)" \
4157		-relief sunken -bg $TBG -fg $TFG
4158		text $p3.row0 -height 12 -relief sunken
4159
4160	$p3.row0 insert end "-DBITSTATE -DPUTPID             # basic dfs\n"
4161	$p3.row0 insert end "-DBITSTATE -DPUTPID -DREVERSE   # reversed transition ordering\n"
4162	$p3.row0 insert end "-DBITSTATE -DPUTPID -DT_REVERSE # reversed process ordering\n"
4163	$p3.row0 insert end "-DBITSTATE -DPUTPID -DREVERSE -DT_REVERSE       # both\n"
4164	$p3.row0 insert end "-DBITSTATE -DPUTPID -DP_RAND -DT_RAND   # same series with randomization\n"
4165	$p3.row0 insert end "-DBITSTATE -DPUTPID -DP_RAND -DT_RAND -DT_REVERSE\n"
4166	$p3.row0 insert end "-DBITSTATE -DPUTPID -DP_RAND -DT_RAND -DREVERSE\n"
4167	$p3.row0 insert end "-DBITSTATE -DPUTPID -DP_RAND -DT_RAND -DREVERSE -DT_REVERSE\n"
4168
4169	pack $p3.limits $p3.row0 -side top -fill x -expand no
4170
4171#	frame $p3.row2
4172#		label $p3.row2.k1 -text "runtime options" -bg $TBG -fg $TFG
4173#		entry $p3.row2.e1 -relief sunken -bg $TBG -fg $TFG
4174#		$p3.row2.e1 insert end "-c1 -x -n"
4175#		pack $p3.row2.k1 $p3.row2.e1 -side top -fill x -expand no
4176#	pack $p3.row2 -side top -fill x -expand no
4177
4178	set vw  [PanedWindow $t.bottom -side left -activator button ]
4179
4180	set p8  [$vw add -minsize 100]
4181	set p9  [$vw add -minsize 100]
4182
4183        set s11  [ScrolledWindow $p8.so -size $ScrollBarSize]	;# so - swarm output
4184        set so   [text $s11.lb -height 5 -highlightthickness 3 -font $HV1]
4185        $s11 setwidget $so
4186
4187        set s22  [ScrolledWindow $p9.sr -size $ScrollBarSize]	;# sr - swarm run
4188        set sr   [text $s22.lb -highlightthickness 0 -bg $CBG -fg $CFG -font $HV1]
4189        $s22 setwidget $sr
4190
4191	$so insert end "swarm setup output\n"
4192	$sr insert end "swarm run output\n"
4193
4194	set errmsg ""
4195	# a bit overkill, but execs compiled with gcc
4196	# behave differently from those compiled with cl
4197	# complaints about missing tty, for instance
4198	# spin on cygwin is compiled with cl, swarm with gcc
4199
4200	if {[auto_execok $SWARM] == ""} {
4201			$sr insert end "no 'swarm' command is found\n"
4202			$sr insert end "available from: http://spinroot.com/swarm/\n"
4203	} else {
4204		catch { set fd [open "|$SWARM -V" r] } errmsg
4205		if {$fd == -1} {
4206			$sr insert end "$errmsg\n"
4207		} else {
4208			while {[gets $fd line] > -1} {
4209				$sr insert end "$line\n"
4210			}
4211			catch " close $fd "
4212	}	}
4213
4214	pack $s11 -fill both -expand yes
4215	pack $s22 -fill both -expand yes
4216	pack $vw  -fill both -expand yes
4217
4218}
4219
4220proc explain0 {} {
4221	global vo
4222
4223	$vo insert end "\n"
4224	$vo insert end "\tPhysical Memory Available:\n"
4225	$vo insert end "\tSet this number to amount of physical (not virtual) memory\n"
4226	$vo insert end "\tin your system, in MegaBytes, and leave it there for all runs.\n"
4227	$vo insert end "\n"
4228	$vo insert end "\tWhen the limit is reached, the verification is stopped to\n"
4229	$vo insert end "\tavoid trashing.\n"
4230	$vo insert end "\n"
4231	$vo insert end "\tIf an exhaustive verification cannot be completed due to\n"
4232	$vo insert end "\tlack of memory, select a different storage mode.\n\n"
4233	$vo yview end
4234}
4235
4236proc explain1 {} {
4237	global vo
4238
4239	$vo insert end "\tEstimated State Space Size:\n"
4240	$vo insert end "\tThis parameter is used to calculate the size of the\n"
4241	$vo insert end "\thash-table. It results in a selection of a numeric argument\n"
4242	$vo insert end "\tfor the -w flag of the verifier. Setting it too high may\n"
4243	$vo insert end "\tcause an out-of-memory error with zero states reached\n"
4244	$vo insert end "\t(meaning that the verification could not be started).\n"
4245	$vo insert end "\tSetting it too low can cause inefficiencies due to\n"
4246	$vo insert end "\thash collisions.\n"
4247	$vo insert end "\t\n"
4248	$vo insert end "\tWhen using bitstate, start with the default\n"
4249	$vo insert end "\tsetting.  After a run completes successfully,\n"
4250	$vo insert end "\tdouble the estimate, and see if the number of reached\n"
4251	$vo insert end "\tstated changes much.  Continue to do this until\n"
4252	$vo insert end "\tit stops changing, or until you reach the memory bound.\n"
4253	$vo insert end "\t\n"
4254	$vo insert end "\tiSpin uses the closest power of two to determine the parameter\n"
4255	$vo insert end "\tgiven to the -w flag that is used for the run.\n\n"
4256	$vo yview end
4257}
4258
4259proc explain2 {} {
4260	global vo
4261	$vo insert end "\tMaximum Search Depth:\n"
4262	$vo insert end "\tThis number determines the size of the depth-first\n"
4263	$vo insert end "\tsearch stack that is used during the verification.\n"
4264	$vo insert end "\tA larger number increases the memory requirements, and\n"
4265	$vo insert end "\ta lower number decreases it.  When there seems not to be\n"
4266	$vo insert end "\tsufficient memory for the search depth needed, reduce\n"
4267	$vo insert end "\treduce the estimated state space size to free some\n"
4268	$vo insert end "\tmore memory for the stack, or change the storage mode.\n"
4269	$vo insert end "\t\n"
4270	$vo insert end "\tIf you hit the maximum search depth during a verification\n"
4271	$vo insert end "\t(noted as 'Search not completed' or 'Search Truncated'\n"
4272	$vo insert end "\tin the verification output) without finding an error,\n"
4273	$vo insert end "\tincrease the search depth parameter and repeat the run.\n\n"
4274	$vo yview end
4275}
4276
4277proc explain3 {} {
4278	global vo
4279
4280	$vo insert end "\tNumber of hash functions:\n"
4281	$vo insert end "\tThis number determines how many bits are set per\n"
4282	$vo insert end "\tstate when in Bitstate verification mode. The default is 3,\n"
4283	$vo insert end "\tbut you can use any number greater to or equal to 1.\n"
4284	$vo insert end "\tAt the end of a Bitstate verification run, the verifier\n"
4285	$vo insert end "\tcan issue a recommendation for a different setting of\n"
4286	$vo insert end "\tthis parameter (specified with the -k flag), if this can\n"
4287	$vo insert end "\timprove coverage.\n\n"
4288	$vo yview end
4289}
4290
4291proc explain4 {} {
4292	global vo
4293
4294	$vo insert end "\tSize for Minimized Automata:\n"
4295	$vo insert end "\tWhen using the minimized automata storage mode, you should\n"
4296	$vo insert end "\tset this parameter to be equal to the statevector size at first.\n"
4297	$vo insert end "\tAt the end of the run, the verifier will then report if a smaller\n"
4298	$vo insert end "\tnumber can also be used. The smaller the number the faster the run.\n\n"
4299	$vo yview end
4300}
4301
4302proc explain5 {} {
4303	global vo
4304
4305	$vo insert end "\tExtra Verifier Generator Options:\n"
4306	$vo insert end "\tPossible options include:\n"
4307	$vo insert end "\t-o1	to disable dataflow optimizations\n"
4308	$vo insert end "\t-o2	to disable dead-variable elimination\n"
4309	$vo insert end "\t-o3	to disable statement merging (which improves source-line references)\n\n"
4310	$vo yview end
4311}
4312
4313proc explain6 {} {
4314	global vo
4315
4316	$vo insert end "\tExtra Compile-time Directives:\n"
4317	$vo insert end "\tFor possible options see:\n"
4318	$vo insert end "\thttp://spinroot.com/spin/Man/Pan.html#B\n\n"
4319	$vo yview end
4320}
4321
4322proc explain7 {} {
4323	global vo
4324
4325	$vo insert end "\tExtra Run-time Options:\n"
4326	$vo insert end "\tPossible options include:\n"
4327	$vo insert end "\t-hN	use a different hash-function (N: 1..32, default 1)\n"
4328	$vo insert end "\t-J	reverse evaluation order on nested unless structures\n"
4329	$vo insert end "\t-q	require channels to be empty in valid endstates\n"
4330	$vo insert end "\t-QN	try to stop the run after N minutes\n"
4331	$vo insert end "\t-tSuf	use Suf as a suffix on trail files instead of .trail\n"
4332	$vo insert end "\t-T	create trail files in read-only mode\n"
4333	$vo insert end "\t-x	do not overwrite an existing trail file\n\n"
4334	$vo yview end
4335}
4336
4337proc ver_help {} {
4338	global vo
4339
4340	$vo insert end "\tHelp with Verification Complexity:\n"
4341	$vo insert end "\t---------------------------------------\n"
4342	$vo insert end "\tWhen a verification cannot be completed because it\n"
4343	$vo insert end "\truns out of memory or you run out of time, there are\n"
4344	$vo insert end "\tsome useful strategies that can be tried to restore tractability.\n"
4345	$vo insert end "\n"
4346	$vo insert end "\t0. Run the Redundancy Check (in the Edit/View tab) to see if you can\n"
4347	$vo insert end "\tsimplify the model and still prove the same properties.\n"
4348	$vo insert end "\n"
4349	$vo insert end "\t1. Try to make the model more general.\n"
4350	$vo insert end "\tRemember that you are constructing a verification model and not\n"
4351	$vo insert end "\tan implementation.  The model checker is good at proving properties\n"
4352	$vo insert end "\tof *interactions* in a distributed system (the implicit assumptions\n"
4353	$vo insert end "\tthat processes make about each other) -- it is generally not strong\n"
4354	$vo insert end "\tin proving things about *computations*, data dependencies etc.\n"
4355	$vo insert end "\n"
4356	$vo insert end "\t2. Remove everything that is not directly related to the property\n"
4357	$vo insert end "\tyou are trying to prove: redundant computations, redundant data. \n"
4358	$vo insert end "\t*Avoid counters*; avoid incrementing variables that are used for\n"
4359	$vo insert end "\tonly book-keeping purposes.\n"
4360	$vo insert end "\tThe Syntax Check option (Edit/View tab) warns about the gravest offenses.\n"
4361	$vo insert end "\n"
4362	$vo insert end "\t3. Asynchronous channels can be a significant source of complexity in\n"
4363	$vo insert end "\tverification.  Use *synchronous channels* where possible.  Reduce the\n"
4364	$vo insert end "\tnumber of slots in asynchronous channels to a minimum (use 2, or 3\n"
4365	$vo insert end "\tslots to get started).\n"
4366	$vo insert end "\n"
4367	$vo insert end "\t4. Look for processes that merely transfer messages. Consider if\n"
4368	$vo insert end "\tyou can remove processes that only copy incoming messages from\n"
4369	$vo insert end "\tone channel into another, by letting the sender generate the\n"
4370	$vo insert end "\tfinal message right away.  If the intermediate process makes\n"
4371	$vo insert end "\tchoices (e.g., to delete or duplicate, etc.), let the sender\n"
4372	$vo insert end "\tmake that choice, rather than an intermediate process.\n"
4373	$vo insert end "\n"
4374	$vo insert end "\t5. Combine local computations into atomic, or d_step, sequences.\n"
4375	$vo insert end "\n"
4376	$vo insert end "\t6. Avoid leaving scratch data around in variables.  You can often reduce\n"
4377	$vo insert end "\tthe number of states by, for instance, resetting local variables\n"
4378	$vo insert end "\tthat are used inside atomic sequences to zero at the end of those\n"
4379	$vo insert end "\tsequences; so that the scratch values aren't visible outside the\n"
4380	$vo insert end "\tsequence.  Consider using the predefined variable \"_\" as a write-only\n"
4381	$vo insert end "\tscratch variable where possible.\n"
4382	$vo insert end "\n"
4383	$vo insert end "\t7. Try to combine the behavior of two processes into one.\n"
4384	$vo insert end "\tGeneralize behavior. Focus on coordination aspects\n"
4385	$vo insert end "\t(i.e., the interfaces between processes, rather than the local\n"
4386	$vo insert end "\tcomputations inside processes).\n"
4387	$vo insert end "\n"
4388	$vo insert end "\t8. Try to exploit the partial order reduction strategies.\n"
4389	$vo insert end "\tUse the xr and xs assertions where possible (see the online manpages\n"
4390	$vo insert end "\tat spinroot.com; avoid sharing channels between multiple receivers or\n"
4391	$vo insert end "\tmultiple senders.\n"
4392	$vo insert end "\tAvoid merging independent data-streams into a single shared channel.\n"
4393	$vo yview end
4394}
4395
4396proc del_v_panel {n} {
4397	global vpanel
4398
4399	if {$n == 1} {
4400		catch { destroy $vpanel.top.middle }
4401	}
4402	if {$n == 2} {
4403		catch { destroy $vpanel.top.third }
4404	}
4405	if {$n == 3} {
4406		catch { destroy $vpanel.top.right }
4407	}
4408}
4409
4410proc toggle_a {n} {
4411	global V_Panel_1 V_Panel_3 vpanel LIB NBG HV0 NFG
4412
4413	if {$n == 1} {
4414		if {$V_Panel_1} {
4415			set V_Panel_1 0
4416			set p6 $vpanel.top.middle
4417			catch {
4418				destroy $p6.er
4419				destroy $p6.lb
4420				destroy $p6.row0
4421				destroy $p6.row1
4422				destroy $p6.row2
4423				destroy $p6.row4
4424				destroy $p6.row5
4425				destroy $p6.row7
4426				destroy $p6.row8
4427				destroy $p6.rowA
4428				destroy $p6.row66
4429			}
4430
4431			frame $p6.row66 -bg $LIB
4432				button $p6.row66.a1 -text "Show\nError\nTrapping\nOptions" \
4433					-command "toggle_a 1" \
4434					-fg white -bg black -activeforeground $NBG \
4435					-activebackground $NFG -font $HV0
4436				pack $p6.row66.a1 -side left -fill x -expand yes
4437			pack $p6.row66 -side top -fill x -expand yes
4438		} else {
4439			set V_Panel_1 1
4440			$vpanel.top.middle.row66.a1 configure -text "Remove"
4441			advanced_1
4442	}	}
4443
4444	if {$n == 3} {
4445		if {$V_Panel_3} {
4446			set V_Panel_3 0
4447			set p6 $vpanel.top.right
4448			catch {
4449				destroy $p6.t
4450				for {set i 0} {$i <= 7} {incr i} {
4451					destroy $p6.row$i
4452				}
4453				destroy $p6.row66
4454			}
4455
4456			frame $p6.row66 -bg $LIB
4457				button $p6.row66.a3 -text "Show\nAdvanced\nParameter\nSettings" \
4458					-command "toggle_a 3" \
4459					-fg white -bg black -activeforeground $NBG \
4460					-activebackground $NFG -font $HV0
4461				pack $p6.row66.a3 -side left -fill x -expand yes
4462			pack $p6.row66 -side top -fill x -expand yes
4463		} else {
4464			set V_Panel_3 1
4465			$vpanel.top.right.row66.a3 configure -text "Remove"
4466			advanced_3
4467	}	}
4468
4469}
4470
4471set peg 0
4472set vranges 0
4473set sv_mode 0
4474set estop 0
4475set q_mode 0
4476
4477proc advanced_1 {} {
4478	global LIB TFG NFG NBG HV0 vpanel V_Panel_1
4479	global peg sv_mode estop vranges q_mode
4480
4481	set t $vpanel
4482
4483	set p6 $t.top.middle
4484	label $p6.er -text "Advanced: Error Trapping" -relief raised -bg $LIB
4485	frame $p6.row0 -bg $LIB
4486		radiobutton $p6.row0.ds -variable estop -value 1 -text "don't stop at errors" -bg $LIB -fg $TFG
4487	pack $p6.row0.ds -side left -fill x -expand no
4488
4489	frame $p6.row1 -bg $LIB
4490		radiobutton $p6.row1.st -variable estop -value 0 -text "stop at error nr:" -bg $LIB -fg $TFG
4491		entry $p6.row1.nr
4492		$p6.row1.nr insert end "1"
4493	pack $p6.row1.st -side left -fill x -expand no
4494	pack $p6.row1.nr -side right -fill x -expand yes
4495
4496	frame $p6.row2 -bg $LIB
4497		checkbutton $p6.row2.se -variable sv_mode -text "save all error-trails" -bg $LIB -fg $TFG
4498		pack $p6.row2.se -side left -fill x -expand no
4499	frame $p6.row4 -bg $LIB
4500		checkbutton $p6.row4.ac -variable peg -text "add complexity profiling" -bg $LIB -fg $TFG
4501		pack $p6.row4.ac -side left -fill x -expand no
4502	frame $p6.row5 -bg $LIB
4503		checkbutton $p6.row5.vr -variable vranges -text "compute variable ranges" -bg $LIB -fg $TFG
4504		pack $p6.row5.vr -side left -fill x -expand no
4505
4506	pack	$p6.er $p6.row0 $p6.row1 $p6.row2 $p6.row4 $p6.row5 \
4507		-side top -fill x -expand yes
4508
4509	label $p6.lb -text "A Full Channel" -relief raised -bg $LIB -fg $TFG
4510	frame $p6.row7 -bg $LIB
4511		radiobutton $p6.row7.b -variable q_mode -value 0 -text "blocks new msgs" -bg $LIB -fg $TFG
4512		pack $p6.row7.b -side left -fill x -expand no
4513	frame $p6.row8 -bg $LIB
4514		radiobutton $p6.row8.l -variable q_mode -value 1 -text "loses new msgs" -bg $LIB -fg $TFG
4515		pack $p6.row8.l -side left -fill x -expand no
4516
4517	frame $p6.rowA -bg $LIB
4518	button $p6.rowA.tb -text "State Tables" \
4519		-command " run_tbl $t " \
4520		-fg white -bg grey -activeforeground $NBG -activebackground $NFG -font $HV0
4521	button $p6.rowA.clr -text "Clear" -command " do_clear " \
4522		-fg white -bg grey -activeforeground $NBG -activebackground $NFG -font $HV0
4523	button $p6.rowA.hlp -text "Help" -command " ver_help " \
4524		-fg white -bg grey -activeforeground $NBG -activebackground $NFG -font $HV0
4525	pack $p6.rowA.tb $p6.rowA.clr $p6.rowA.hlp -side left -fill x -expand yes
4526
4527	pack $p6.lb $p6.row7 $p6.row8 $p6.rowA -side top -fill x -expand no
4528}
4529
4530proc advanced_2 {} {
4531	global TFG NFG NBG HV0 vpanel TBG
4532	global po_mode bf_mode bc_mode it_mode u_mode
4533
4534	set LIB $TBG	;# overrides global
4535	set t $vpanel
4536
4537	set p5 $t.top.third
4538	label $p5.sm -text "Search Mode" -relief raised -bg $LIB -fg $TFG
4539
4540	frame $p5.row5 -bg $LIB
4541		label $p5.row5.sp -width 1 -bg $LIB -fg $TFG
4542		checkbutton $p5.row5.po -variable po_mode -text "+ partial order reduction" -bg $LIB -fg $TFG
4543		pack $p5.row5.sp $p5.row5.po -side left -fill x -expand no
4544	frame $p5.row6 -bg $LIB
4545		radiobutton $p5.row6.dfs -variable bf_mode -value 0 -text "depth-first search" -bg $LIB -fg $TFG
4546		pack $p5.row6.dfs -side left -fill x -expand no
4547
4548	frame $p5.row60 -bg $LIB
4549		label $p5.row60.sp -width 1 -bg $LIB -fg $TFG
4550		checkbutton $p5.row60.fs -variable bc_mode -text "+ bounded context switching" -bg $LIB -fg $TFG
4551		pack $p5.row60.sp $p5.row60.fs -side left -fill x -expand no
4552
4553	frame $p5.rowB -bg $LIB
4554		label $p5.rowB.sp -width 6 -bg $LIB -fg $TFG
4555		label $p5.rowB.nm -text "with bound:" -bg $LIB -fg $TFG
4556		entry $p5.rowB.ent -relief sunken -width 8
4557		$p5.rowB.ent insert end "0"
4558		pack $p5.rowB.sp $p5.rowB.nm -side left -fill x -expand no
4559		pack $p5.rowB.ent -side left -fill x -expand yes
4560
4561	frame $p5.row61 -bg $LIB
4562		label $p5.row61.sp -width 1 -bg $LIB -fg $TFG
4563		checkbutton $p5.row61.fs -variable it_mode -text "+ iterative search for short trail" -bg $LIB -fg $TFG
4564		pack $p5.row61.sp $p5.row61.fs -side left -fill x -expand no
4565	frame $p5.row62 -bg $LIB
4566		label $p5.row62.sp -width 1 -bg $LIB -fg $TFG
4567		checkbutton $p5.row62.po -variable po_mode -text "+ partial order reduction" -bg $LIB -fg $TFG
4568		pack $p5.row62.sp $p5.row62.po -side left -fill x -expand no
4569
4570	frame $p5.row7 -bg $LIB
4571		radiobutton $p5.row7.bfs -variable bf_mode -value 1 -text "breadth-first search" -bg $LIB -fg $TFG
4572		pack $p5.row7.bfs -side left -fill x -expand no
4573	frame $p5.row8 -bg $LIB
4574		checkbutton $p5.row8.ur -variable u_mode -text "report unreachable code" -bg $LIB -fg $TFG
4575		pack $p5.row8.ur -side left -fill x -expand no
4576
4577	frame $p5.row9 -bg $LIB
4578		entry  $p5.row9.en -relief sunken -width 12
4579		button $p5.row9.lb -text "Save Result in:" \
4580			-command " save_in $p5.row9.en" \
4581			-bg grey -fg white \
4582			-activeforeground $NBG -activebackground $NFG -font $HV0
4583		$p5.row9.en insert end "pan.out"
4584		pack $p5.row9.lb $p5.row9.en -side left -fill y -expand yes
4585
4586	pack	$p5.sm $p5.row6 $p5.row62 $p5.row60 $p5.rowB $p5.row61 $p5.row7 $p5.row5 $p5.row8 $p5.row9 \
4587		-side top -fill x -expand no
4588}
4589
4590proc advanced_3 {} {
4591	global bet ival expl LIB TFG NFG NBG HV0 vpanel V_Panel_3
4592
4593	set t $vpanel
4594
4595	set p7 $t.top.right
4596	label $p7.t -text "Advanced: Parameters" -relief raised -bg $LIB -fg $TFG
4597	pack $p7.t -side top -fill x -expand no
4598
4599	for {set i 0} {$i <= 7} {incr i} {
4600		frame $p7.row$i -bg $LIB
4601		label  $p7.row$i.lbl -text $bet($i) -bg $LIB -fg $TFG
4602		entry  $p7.row$i.ent -width 20
4603			$p7.row$i.ent insert end $ival($i)
4604		button $p7.row$i.exp -text $expl($i) -command " explain$i " -bg $LIB -fg $TFG
4605		pack $p7.row$i.lbl -side left -fill x -expand no
4606		pack $p7.row$i.exp -side right -fill x -expand no
4607		pack $p7.row$i.ent -side right -fill x -expand no
4608		pack $p7.row$i -side top -fill x -expand no
4609	}
4610}
4611
4612proc verify_panel {t} {
4613	global bet ival expl estop s_mode po_mode bf_mode e_mode HV0 HV1 CBG CFG TBG TFG NBG NFG it_mode
4614	global ma_mode cc_mode p_mode c_mode u_mode a_mode x_mode q_mode f_mode bc_mode
4615	global sv_mode vo vr Fname ScrollBarSize peg vranges vpanel
4616	global LTL_Panel V_Panel_1 V_Panel_3 LIB
4617
4618	set vpanel $t
4619
4620	set LIB lightgray	;# background for less important options -- was TBG
4621
4622	frame $t.top -bg $LIB
4623	pack $t.top -side top -fill both -expand no
4624
4625	frame $t.top.left -bg $TBG
4626	frame $t.top.fourth -bg $TBG
4627	frame $t.top.middle -bg $LIB
4628	frame $t.top.third -bg $LIB
4629	frame $t.top.right -bg $LIB
4630	pack $t.top.left $t.top.fourth -side left -fill both -expand yes
4631	pack $t.top.third  -side left -fill both -expand yes
4632	pack $t.top.middle -side left -fill x -expand yes
4633	pack $t.top.right  -side left -fill x -expand yes
4634
4635	set p1 $t.top.left
4636	label $p1.saf -text "Safety" -relief raised -bg $TBG -fg $TFG
4637	label $p1.liv -text "Liveness" -relief raised -bg $TBG -fg $TFG
4638
4639	frame $p1.row0 -bg $TBG
4640		radiobutton $p1.row0.sf -variable p_mode -value 0 -text "safety" -bg $TBG -fg $TFG
4641		pack $p1.row0.sf -side left -fill x -expand no
4642	frame $p1.row1 -bg $TBG
4643		label $p1.row1.sp -width 1 -bg $TBG -fg $TFG
4644		checkbutton $p1.row1.av -variable a_mode -text "+ assertion violations" -bg $TBG -fg $TFG
4645		pack $p1.row1.sp $p1.row1.av -side left -fill x -expand no
4646	frame $p1.row9 -bg $TBG
4647		label $p1.row9.sp -width 1 -bg $TBG -fg $TFG
4648		checkbutton $p1.row9.xr -variable x_mode -text "+ xr/xs assertions" -bg $TBG -fg $TFG
4649		pack $p1.row9.sp $p1.row9.xr -side left -fill x -expand no
4650	frame $p1.row2 -bg $TBG
4651		label $p1.row2.sp -width 1 -bg $TBG -fg $TFG
4652		checkbutton $p1.row2.ie -variable e_mode -text "+ invalid endstates (deadlock)" -bg $TBG -fg $TFG
4653		pack $p1.row2.sp $p1.row2.ie -side left -fill x -expand no
4654
4655	pack $p1.saf $p1.row0 $p1.row2 $p1.row1 $p1.row9 -side top -fill x -expand no
4656
4657	frame $p1.row3 -bg $TBG
4658		radiobutton $p1.row3.np -variable p_mode -value 1 -text "non-progress cycles" -bg $TBG -fg $TFG
4659		pack $p1.row3.np -side left -fill x -expand no
4660	frame $p1.row4 -bg $TBG
4661		radiobutton $p1.row4.ac -variable p_mode -value 2 -text "acceptance cycles" -bg $TBG -fg $TFG
4662		pack $p1.row4.ac -side left -fill x -expand no
4663	frame $p1.row5 -bg $TBG
4664	#	label $p1.row5.sp -width 1 -bg $TBG -fg $TFG
4665		checkbutton $p1.row5.wf -variable f_mode -text "enforce weak fairness constraint" -bg $TBG -fg $TFG
4666		pack $p1.row5.wf -side left -fill x -expand no
4667
4668	pack $p1.liv $p1.row3 $p1.row4 $p1.row5 -side top -fill x -expand no
4669
4670	set p10 $t.top.fourth
4671	label $p10.alg -text "Storage Mode" -relief raised -bg $TBG -fg $TFG
4672
4673	frame $p10.row0 -bg $TBG
4674		radiobutton $p10.row0.ex -variable s_mode -value 0 -text "exhaustive" -bg $TBG -fg $TFG
4675		pack $p10.row0.ex -side left -fill x -expand no
4676#	frame $p10.row1 -bg $TBG
4677#		radiobutton $p10.row1.bs -variable s_mode -value 1 -text "bitstate" -bg $TBG -fg $TFG
4678#		pack $p10.row1.bs -side left -fill x -expand no
4679	frame $p10.row2 -bg $TBG
4680		radiobutton $p10.row2.hc -variable s_mode -value 2 -text "hash-compact" -bg $TBG -fg $TFG
4681		radiobutton $p10.row2.bs -variable s_mode -value 1 -text "bitstate/supertrace" -bg $TBG -fg $TFG
4682		pack $p10.row2.hc $p10.row2.bs -side left -fill x -expand no
4683	frame $p10.row3 -bg $TBG
4684		label $p10.row3.sp -width 1 -bg $TBG -fg $TFG
4685		checkbutton $p10.row3.ma -variable ma_mode -text "+ minimized automata (slow)" -bg $TBG -fg $TFG
4686		pack $p10.row3.sp $p10.row3.ma -side left -fill x -expand no
4687	frame $p10.row4 -bg $TBG
4688		label $p10.row4.sp -width 1 -bg $TBG -fg $TFG
4689		checkbutton $p10.row4.cl -variable cc_mode -text "+ collapse compression" -bg $TBG -fg $TFG
4690		pack $p10.row4.sp $p10.row4.cl -side left -fill x -expand no
4691
4692	frame $p10.row6 -bg $TBG
4693	button $p10.row6.go -text "Run" \
4694		-command " run_ver $t " \
4695		-fg $NFG -bg $NBG -activeforeground $NBG -activebackground $NFG -font $HV0
4696	button $p10.row6.no -text "Stop" \
4697		-command " stop_ver $t " \
4698		-fg $NFG -bg $NBG -activeforeground $NBG -activebackground $NFG -font $HV0
4699
4700	pack $p10.row6.no $p10.row6.go -side right -fill x -expand yes
4701
4702
4703	pack  $p10.alg $p10.row0 $p10.row3 $p10.row4 $p10.row2 \
4704		-side top -fill x -expand no
4705
4706	label $p10.nc -text "Never Claims" -relief raised -bg $TBG -fg $TFG
4707
4708	frame $p10.row9 -bg $TBG
4709	if {$LTL_Panel} {
4710		radiobutton $p10.row9.nc -variable c_mode -value 1 -text "use claim from LTL panel:" -bg $TBG -fg $TFG
4711		pack $p10.row9.nc -side left -fill x -expand no
4712	} else {
4713		radiobutton $p10.row9.nc -variable c_mode -value 1 -text "use claim" -bg $TBG -fg $TFG
4714		pack $p10.row9.nc -side left -fill x -expand no
4715		frame $p10.rowA -bg $TBG
4716		label $p10.rowA.lb -text "  claim name (opt):" -bg $TBG -fg $TFG
4717		entry $p10.rowA.nr
4718		pack $p10.rowA.lb -side left -fill x -expand no
4719		pack $p10.rowA.nr -side left -fill x -expand yes
4720	}
4721
4722#	frame $p10.row10 -bg $TBG
4723#		radiobutton $p10.row10.nc -variable c_mode -value 2 \
4724#			-text "use (only) product of claims in spec" -bg $TBG -fg $TFG
4725#		pack $p10.row10.nc -side left -fill x -expand no
4726
4727	frame $p10.row11 -bg $TBG
4728		radiobutton $p10.row11.nc -variable c_mode -value 0 \
4729			-text "do not use a never claim or ltl property" -bg $TBG -fg $TFG
4730		pack $p10.row11.nc -side left -fill x -expand no
4731
4732	pack  $p10.nc $p10.row11 $p10.row9 \
4733		-side top -fill x -expand no
4734
4735	if {$LTL_Panel == 0} {
4736		pack $p10.rowA -side top -fill x -expand no
4737	}
4738
4739	set p6 $t.top.middle
4740	frame $p6.row66 -bg $LIB
4741		button $p6.row66.a1 -text "Show\nError\nTrapping\nOptions" \
4742			-command "toggle_a 1" \
4743			-fg white -bg black -activeforeground $NBG \
4744			-activebackground $NFG -font $HV0
4745		pack $p6.row66.a1 -side left -fill x -expand yes
4746	pack $p6.row66 -side top -fill x -expand yes
4747
4748	set p6 $t.top.right
4749	frame $p6.row66 -bg $LIB
4750		button $p6.row66.a3 -text "Show\nAdvanced\nParameter\nSettings" \
4751			-command "toggle_a 3" \
4752			-fg white -bg black -activeforeground $NBG \
4753			-activebackground $NFG -font $HV0
4754		pack $p6.row66.a3 -side left -fill x -expand yes
4755	pack $p6.row66 -side top -fill x -expand yes
4756
4757	pack $p10.row6 -side bottom -fill x -expand no
4758
4759	advanced_2
4760
4761	if {$V_Panel_1} {
4762		advanced_1
4763	}
4764	if {$V_Panel_3} {
4765		advanced_3
4766	}
4767###
4768	set vw  [PanedWindow $t.bottom -side top -activator button ]
4769
4770	set p9  [$vw add -minsize 100]
4771	set p8  [$vw add -minsize 100]
4772
4773        set s11  [ScrolledWindow $p8.vo -size $ScrollBarSize]	;# vo - verification output
4774        set vo   [text $s11.lb -height 6 -width 100 -highlightthickness 3 -bg $CBG -fg $CFG -font $HV1]
4775        $s11 setwidget $vo
4776
4777        set s22  [ScrolledWindow $p9.vr -size $ScrollBarSize]	;# vr - verification reference
4778        set vr   [text $s22.lb -height 35 -highlightthickness 0 -font $HV1]
4779        $s22 setwidget $vr
4780
4781        pack $s11 -fill both -expand yes
4782        pack $s22 -fill both -expand yes
4783	pack $vw  -fill both -expand yes
4784
4785	$vo insert end "verification result:\n"
4786	$vr insert end "model source:\n"
4787}
4788
4789proc save_in {v} {
4790	global vo
4791
4792	set f [$v get]
4793	if {$f == ""} {
4794		return
4795	}
4796	add_log "save verification output in $f" 0
4797	if [ catch {set fd [open $f w]} errmsg ] {
4798		add_log $errmsg 0
4799		return
4800	}
4801	puts $fd [$vo get 0.0 end]
4802	catch { close $fd }
4803}
4804
4805proc do_clear {} {
4806	global vo
4807	$vo delete 0.0 end
4808}
4809
4810proc output_filters {x} {
4811	global TBG TFG
4812
4813	set fl $x.filters
4814	frame $fl -bg $TBG
4815	pack $fl -padx 1 -pady 1 -side left -fill both -expand no
4816
4817	label $fl.lbl -text "Output Filtering (reg. exps.)" -relief raised -bg $TBG -fg $TFG
4818	pack $fl.lbl -side top -fill x -expand no
4819
4820	add_frame $fl.pids	"process ids:"
4821	add_frame $fl.qids	"queue ids:"
4822	add_frame $fl.vars	"var names:"
4823	add_frame $fl.track	"tracked variable:"
4824	add_frame $fl.scale	"track scaling:"
4825}
4826
4827proc find_trail {e} {
4828	set ftypes {
4829		{{Spin Trail File Format} {.trail} }
4830		{{All Files}	*}
4831	}
4832	switch -- [set file [tk_getOpenFile -filetypes $ftypes]] "" return
4833	catch { $e delete 0.0 end }
4834	catch { $e insert end $file }
4835}
4836
4837proc setup_controls {x} {
4838	global TBG TFG NBG NFG
4839
4840	frame $x.run -bg $TBG
4841	pack $x.run -padx 1 -pady 1 -side left -fill both -expand no
4842
4843	frame $x.run.ctl -bg $TBG
4844	button $x.run.ctl.run -width 12 -text "(Re)Run" \
4845		-command { run_sim } \
4846		-bg $NBG -fg $NFG -activebackground $NFG -activeforeground $NBG
4847
4848	button $x.run.ctl.step -width 12 -text "Step Forward" \
4849		-bg $NBG -fg grey -activebackground $NFG -activeforeground $NBG
4850
4851	button $x.run.ctl.stop -width 12 -text "Stop" \
4852		-command { set stop 1 } \
4853		-bg $NBG -fg $NFG -activebackground $NFG -activeforeground $NBG
4854
4855	button $x.run.ctl.back -width 12 -text "Step Backward" \
4856		-bg $NBG -fg grey -activebackground $NFG -activeforeground $NBG
4857
4858	button $x.run.ctl.reset -width 12 -text "Rewind" \
4859		-bg $NBG -fg grey -activebackground $NFG -activeforeground $NBG
4860
4861	pack $x.run.ctl -side left -fill both -expand no
4862	pack	$x.run.ctl.run \
4863		$x.run.ctl.stop \
4864		$x.run.ctl.reset \
4865		$x.run.ctl.step \
4866		$x.run.ctl.back \
4867		-side top -fill y -expand yes
4868}
4869
4870proc inspect_ltl {et ns} {
4871
4872	set x [$et get]
4873
4874	regsub -all {\&\&} "$x" " " y; set x $y
4875	regsub -all {\|\|} "$x" " " y; set x $y
4876	regsub -all {\/\\} "$x" " " y; set x $y
4877	regsub -all {\\\/} "$x" " " y; set x $y
4878	regsub -all {\!}  "$x" " " y; set x $y
4879	regsub -all {<->} "$x" " " y; set x $y
4880	regsub -all {\->}  "$x" " " y; set x $y
4881	regsub -all {\[\]} "$x" " " y; set x $y
4882	regsub -all {\<\>} "$x" " " y; set x $y
4883	regsub -all {[()]} "$x" " " y; set x $y
4884	regsub -all {\ \ *} "$x" " " y; set x $y
4885	regsub -all { U} "$x" " " y; set x $y
4886	regsub -all { V} "$x" " " y; set x $y
4887	regsub -all { X} "$x" " " y; set x $y
4888
4889	set predefs " np_ true false "
4890
4891	set k [split $x " "]
4892	set j [llength $k]
4893	set line [$ns get 0.0 end]
4894	for {set i 0} {$i < $j} {incr i} {
4895		if {[string length [lindex $k $i]] > 0 \
4896		&&  [string first " [lindex $k $i] " $predefs] < 0} {
4897		  set pattern "#define [lindex $k $i]"
4898		  if {[string first $pattern $line] < 0} {
4899			catch {
4900			$ns insert end "$pattern\t?\n"
4901			}
4902			set line [$ns get 0.0 end]
4903	}	} }
4904}
4905
4906set ltl_cnt 0
4907proc ltl_log {s} {
4908	global ltl_cnt log_pan
4909
4910	incr ltl_cnt
4911	$log_pan insert end "$ltl_cnt $s\n"
4912	$log_pan yview end
4913	update
4914}
4915
4916proc gen_claim {et nc ns} {
4917	global negate_ltl
4918
4919	inspect_ltl $et $ns
4920	set formula [$et get]
4921
4922	if {$negate_ltl == "1"} {
4923		set formula "!($formula)"
4924	}
4925
4926	$nc delete 0.0 end
4927
4928	catch {
4929		set fd [open "|spin -f \"($formula)\"" r]
4930		while {[eof $fd] == 0 && [gets $fd line] > -1} {
4931			$nc insert end $line\n
4932		}
4933		catch "close $fd"
4934	}
4935}
4936
4937proc clear_ltl {t} {
4938	global sym_pan nvr_pan note_pan
4939
4940	$t.left.frm.tmp delete 0 end
4941	$t.left.frm.ent delete 0 end
4942	$sym_pan delete 0.0 end
4943	$nvr_pan delete 0.0 end
4944	$note_pan delete 0.0 end
4945
4946	ltl_log "clear"
4947}
4948
4949proc help_ltl {} {
4950	ltl_log "\tLTL Help"
4951	ltl_log "\tYou can load an LTL template with a previously saved LTL"
4952	ltl_log "\tformula from a file via the Browse button on the upper"
4953	ltl_log "\tright of the LTL Property Manager panel."
4954	ltl_log ""
4955	ltl_log "\tDefine a new LTL formula using lowercase names for the"
4956	ltl_log "\tpropositional symbols, for instance:"
4957	ltl_log "\t	[] (p U q)"
4958	ltl_log "\tThe formula expresses either a positive (desired) or a"
4959	ltl_log "\tnegative (undesired) property of the model.  A positive"
4960	ltl_log "\tproperty is negated automatically by the translator to"
4961	ltl_log "\tconvert it in a never claim (which expresses the"
4962	ltl_log "\tcorresponding negative property (the undesired behavior"
4963	ltl_log "\tthat is claimed 'never' to occur)."
4964	ltl_log ""
4965	ltl_log "\tYou can also avoid the use of propositional symbols by"
4966	ltl_log "\tusing embedded expressions in curly braces, e.g., instead"
4967	ltl_log "\tof defining"
4968	ltl_log "\t	#define p (nr_leaders > 0)"
4969	ltl_log "\tand using p as a propositional symbol in the LTL formula"
4970	ltl_log "\t	<>\[\] p"
4971	ltl_log "\tyou can also use an embedded expression as follows:"
4972	ltl_log "\t	<>\[\] {nr_leaders > 0}"
4973	ltl_log ""
4974	ltl_log "\tWhen you type a <Return> or hit the <click to generate> button"
4975	ltl_log "\tat the bottom of the screen, the formula is converted into"
4976	ltl_log "\ta never-claim, which can be imported into a verification on the"
4977	ltl_log "\tVerification Panel (or saved in a template file for later)."
4978	ltl_log ""
4979	ltl_log "\tIf you're using propositional symbols (p, q, etc.) a definition"
4980	ltl_log "\tfor each symbol used must be given in the top window (macros)"
4981	ltl_log "\tThese definitions become part of the LTL template."
4982	ltl_log "\tEnclose the symbol definitions in round braces, for instance:"
4983	ltl_log ""
4984	ltl_log "\t#define p	(a > b)"
4985	ltl_log "\t#define q	(len(q) < 5)"
4986	ltl_log ""
4987	ltl_log "\tValid temporal logic operators are:"
4988	ltl_log "\t	\[\]  Always (no space between \[ and \])"
4989	ltl_log "\t	<>  Eventually (no space between < and >)"
4990	ltl_log "\t	U   (Strong) Until"
4991	ltl_log "\t	V   The Dual of Until: (p V q) == !(!p U !q)"
4992	ltl_log "\t"
4993	ltl_log "\t	All operators are left-associative."
4994	ltl_log "\t"
4995	ltl_log "\tBoolean Operators:"
4996	ltl_log "\t	&&  Logical And (alternative form: /\\, no spaces)"
4997	ltl_log "\t	!   Logical Negation"
4998	ltl_log "\t	||  Logical Or  (alternative form: \\/, no spaces)"
4999	ltl_log "\t	->  Logical Implication"
5000	ltl_log "\t	<-> Logical Equivalence"
5001	ltl_log ""
5002	ltl_log "\tBoolean Predicates:"
5003	ltl_log "\t	true, false"
5004	ltl_log "\t	any name that starts with a lowercase letter, or"
5005	ltl_log "\t	any state expression enclosed in curly braces {...}"
5006	ltl_log "\t"
5007	ltl_log "\tExamples:"
5008	ltl_log "\t	\[\] p"
5009	ltl_log "\t	!( <> !q )"
5010	ltl_log "\t	p U q"
5011	ltl_log "\t	p U (\[\] (q U r))"
5012	ltl_log "\t	{ a + b == 15 } U { qempty(qin) }"
5013	ltl_log "\t"
5014	ltl_log "\tGeneric types of LTL properties:"
5015	ltl_log "\t	Invariance: \[\] p"
5016	ltl_log "\t	Response:   (p -> \<\> q)"
5017	ltl_log "\t	Precedence: (p -> (q U r))"
5018	ltl_log "\t	Objective:  (p -> \<\> (q || r))"
5019	ltl_log "\t"
5020	ltl_log "\t	Each of the above 4 generic types of properties"
5021	ltl_log "\t	can (and will generally have to) be prefixed by"
5022	ltl_log "\t	temporal operators such as"
5023	ltl_log "\t		\[\], \<\>, \[\]\<\>, \<\>\[\]"
5024	ltl_log "\t	The last (objective) property can be read to mean"
5025	ltl_log "\t	that 'p' is a trigger, or 'enabling' condition that"
5026	ltl_log "\t	determines when the requirement becomes applicable"
5027	ltl_log "\t	(e.g. the sending of a new data message); then 'q'"
5028	ltl_log "\t	can be the fullfillment of the requirement (e.g."
5029	ltl_log "\t	the arrival of the matching acknowledgement), and"
5030	ltl_log "\t	'r' could be a discharging condition that voids the"
5031	ltl_log "\t	applicability of the check (an abort condition)."
5032}
5033
5034proc put_t_name {t file} {
5035
5036	if {[string first "[pwd]/" $file] == 0} {
5037		set prf [string length "[pwd]/"]
5038		set file [string range $file $prf end]
5039	}
5040
5041	$t.left.frm.tmp delete 0 end
5042	$t.left.frm.tmp insert insert "$file"
5043}
5044
5045proc dump_contents {s fd w} {
5046	puts $fd "===start $s==="
5047	puts $fd [$w get 0.0 end]
5048	puts $fd "===end $s==="
5049}
5050
5051proc hunt_for {s fd} {
5052
5053	while {[gets $fd line] > -1} {
5054		if {[string first "$s" $line] >= 0} {
5055			return "$line"
5056		}
5057	}
5058	add_log "restore: $s not found" 0
5059	return ""
5060}
5061
5062proc get_contents {s fd w} {
5063	set found 0
5064
5065	if {[hunt_for "===start $s===" $fd] == ""} {
5066		catch { close $fd }
5067		return 0
5068	}
5069	$w delete 0.0 end
5070
5071	set found 0
5072	while {[gets $fd line] > -1} {
5073		if {[string first "===end $s===" $line] == 0} {
5074			set found 1
5075			break
5076		} else {
5077			$w insert end $line\n
5078	}	}
5079	if {$found == 0} {
5080		add_log "restore: end tag $s not found" 0
5081		catch { close $fd }
5082		return 0
5083	}
5084	return 1
5085}
5086
5087proc get_field {s fd e} {
5088
5089	set want [hunt_for $s $fd]
5090	if {$want == ""} {
5091		add_log "restore: no field $s" 0
5092		return 0
5093	}
5094	set x [string last "\t" $want]
5095	incr x
5096	$e delete 0 end
5097	$e insert end [string range $want $x end]
5098}
5099
5100proc get_var {s fd} {
5101
5102	set want [hunt_for $s $fd]
5103	if {$want == ""} {
5104		add_log "restore: no var $s" 0
5105		return 0
5106	}
5107	set x [string last "\t" $want]
5108	incr x
5109	return [string range $want $x end]
5110}
5111
5112proc restore_session {} {
5113	global Fname Sname twin vwin qwin swin clog x
5114
5115	set ftypes {
5116		{{iSpin Session Format} {.isf} }
5117		{{All Files}	*}
5118	}
5119	switch -- [set f [tk_getOpenFile -filetypes $ftypes]] "" return
5120
5121	if [catch {set fd [open "$f" r]} errmsg] {
5122		add_log $errmsg 1
5123		return
5124	}
5125	if {[gets $fd line] <= -1} {
5126		add_log "restore_session: empty file" 1
5127		return
5128	}
5129# Edit/View
5130	set nx [string first "\t" $line]
5131	if {[string first "Fname" $line] != 0 || $nx != 5} {
5132		add_log "$f is not an ispin session file" 1
5133		add_log "first line is: $line at: [string first "Fname" $line] x: $nx" 0
5134		return
5135	}
5136	incr nx
5137	set Fname [string range $line $nx end]
5138	wm title . "$Fname"
5139
5140	if {[get_contents "Model Spec" $fd $twin] == 0} { return }
5141	if {[get_contents "Model Log"  $fd $clog] == 0} { return }
5142
5143# Simulate
5144global l_typ msc_full var_vals
5145
5146	get_field "Seed"     $fd $x.sms.rnd.fld2	;# random seed value
5147	get_field "Trail"    $fd $x.sms.int.fld4	;# error trail name
5148	get_field "SkipStep" $fd $x.sms.skp.ent		;# steps skipped
5149	get_field "MaxStep"  $fd $x.sms.ub.ent		;# max steps
5150
5151	set var_vals [get_var "VarVals"  $fd]		;# variable values
5152	set l_typ    [get_var "FullQ"    $fd]		;# block/loses choice
5153	set msc_full [get_var "MSC_Full" $fd]		;# MSC+stmnt boolean
5154
5155	get_field "MaxText" $fd	$x.afq.max.me		;# MSC max text width
5156	get_field "Delay"   $fd	$x.afq.delay.me		;# MSC update delay
5157	get_field "Pids"    $fd	$x.filters.pids.ent	;# process ids
5158	get_field "Qids"    $fd	$x.filters.qids.ent	;# queue ids
5159	get_field "Vars"    $fd	$x.filters.vars.ent	;# var names
5160	get_field "Track"   $fd	$x.filters.track.ent	;# tracked var
5161	get_field "Scale"   $fd	$x.filters.scale.ent	;# track scaling
5162
5163	if {[get_contents "Data"   $fd $vwin] == 0} { return }
5164	if {[get_contents "Sim"    $fd $swin] == 0} { return }
5165	if {[get_contents "Queues" $fd $qwin] == 0} { return }
5166
5167# LTL
5168global nvr_pan note_pan sym_pan ltl_main
5169global negate_ltl
5170global LTL_Panel
5171
5172	set LTL_Panel [get_var "LTL_Panel" $fd]
5173
5174	if {$LTL_Panel} {
5175		get_field "Formula"  $fd  $ltl_main.left.frm.ent
5176		get_field "Template" $fd  $ltl_main.left.frm.tmp
5177
5178		set negate_ltl [get_var "All" $fd]		;# all/no executions
5179
5180		if {[get_contents "Symbols" $fd $sym_pan]  == 0} { return }
5181		if {[get_contents "Notes"   $fd $note_pan] == 0} { return }
5182		if {[get_contents "Claim"   $fd $nvr_pan]  == 0} { return }
5183	}
5184
5185# Verification
5186global p_mode a_mode e_mode x_mode f_mode s_mode q_mode
5187global cc_mode ma_mode c_mode estop bf_mode po_mode
5188global bc_mode it_mode u_mode sv_mode peg vranges
5189global vpanel vo
5190	set a_mode  [get_var "a_mode"  $fd]
5191	set bc_mode [get_var "bc_mode" $fd]
5192
5193	get_field "bc_bound" $fd $vpanel.top.third.rowB.ent
5194
5195	set bf_mode [get_var "bf_mode" $fd]
5196	set c_mode  [get_var "c_mode"  $fd]
5197	set cc_mode [get_var "cc_mode" $fd]
5198	set e_mode  [get_var "e_mode"  $fd]
5199	set estop   [get_var "estop"   $fd]
5200	set f_mode  [get_var "f_mode"  $fd]
5201	set it_mode [get_var "it_mode" $fd]
5202	set ma_mode [get_var "ma_mode" $fd]
5203	set p_mode  [get_var "p_mode"  $fd]
5204	set peg     [get_var "peg"     $fd]
5205	set po_mode [get_var "po_mode" $fd]
5206	set q_mode  [get_var "q_mode"  $fd]
5207	set s_mode  [get_var "s_mode"  $fd]
5208	set sv_mode [get_var "sv_mode" $fd]
5209	set u_mode  [get_var "u_mode"  $fd]
5210	set vranges [get_var "vranges" $fd]
5211	set x_mode  [get_var "x_mode"  $fd]
5212
5213global vpanel vo V_Panel_3
5214
5215	if {$V_Panel_3} {
5216		get_field "vrow0" $fd $vpanel.top.right.row0.ent	;# phys mem
5217		get_field "vrow1" $fd $vpanel.top.right.row1.ent	;# state space size
5218		get_field "vrow2" $fd $vpanel.top.right.row2.ent	;# max depth
5219		get_field "vrow3" $fd $vpanel.top.right.row3.ent	;# nr hashfcts
5220		get_field "vrow4" $fd $vpanel.top.right.row4.ent	;# MA size
5221		get_field "vrow5" $fd $vpanel.top.right.row5.ent	;# extra spin options
5222		get_field "vrow6" $fd $vpanel.top.right.row6.ent	;# extra cc options
5223		get_field "vrow7" $fd $vpanel.top.right.row7.ent	;# extra pan options
5224	}
5225
5226	if {[get_contents "VerOut" $fd $vo]  == 0} { return }
5227
5228# Swarm
5229global spanel so sr
5230
5231	get_field "srow0" $fd $spanel.top.left.row0.e0	;# min hashfcts
5232	get_field "srow1" $fd $spanel.top.left.row1.e0	;# max hashfcts
5233	get_field "srow2" $fd $spanel.top.left.row2.e0	;# min search depth
5234	get_field "srow3" $fd $spanel.top.left.row3.e0	;# max search depth
5235	get_field "srow4" $fd $spanel.top.left.row4.e0	;# nr cpus local
5236	get_field "srow5" $fd $spanel.top.left.row5.e0	;# nr cpus remote
5237	get_field "srow6" $fd $spanel.top.left.row6.e0	;# max mem per run
5238	get_field "srow7" $fd $spanel.top.left.row7.e0	;# max runtime
5239
5240	get_field "srow8" $fd $spanel.top.middle.row8.e1	;# hash-factor
5241	get_field "srow9" $fd $spanel.top.middle.row9.e1	;# statevector size in bytes
5242	get_field "srow10" $fd $spanel.top.middle.row10.e1	;# exploration speed
5243
5244	get_field "srow11" $fd $spanel.top.middle.row11.e1	;# extra spin args
5245	get_field "srow12" $fd $spanel.top.middle.row12.e1	;# extra pan args
5246
5247	if {[get_contents "CCopts"  $fd $spanel.top.right.row0]  == 0} { return }
5248	if {[get_contents "SwSetup" $fd $so]  == 0} { return }
5249	if {[get_contents "SwRun"   $fd $sr]  == 0} { return }
5250
5251	catch { close $fd }
5252
5253	add_log "restored session from file $f" 0
5254}
5255
5256proc save_session {n} {
5257	global Fname Sname twin vwin qwin swin clog x
5258	global l_typ msc_full LTL_Panel
5259
5260	set f "$Sname.isf"	;# ispin session file
5261	if {$n == 1} { set f [tk_getSaveFile -defaultextension .isf] }
5262	if {$f == ""} { return }
5263
5264	if {[string first "." $f] < 0} {
5265		set f "$f.isf"
5266	}
5267
5268	if ![file_ok $f] { return }
5269	if [catch {set fd [open $f w]} errmsg] {
5270		add_log $errmsg
5271		return
5272	}
5273	fconfigure $fd -translation lf	;# no cr at end of line
5274
5275	set Sname $f
5276
5277# Global
5278	# PM save colors/fonts/fontsizes, if modified from default
5279# Edit/View
5280	# PM save width/height logwindow in Edit panel
5281		# but $twin configure -height etc. doesnt seem to capture current size
5282		#	set x [$twin configure -height]
5283		#	set n [llength $x]; incr n -1
5284		#	puts $fd "Height [lindex $x $n]" ;# data not current
5285
5286	# filename
5287	puts $fd "Fname	$Fname"
5288	dump_contents "Model Spec" $fd $twin
5289	dump_contents "Model Log"  $fd $clog
5290
5291# Simulate
5292	# PM width/height of text and msc/data/sim/queues panels
5293global var_vals
5294
5295	puts $fd "Seed	[$x.sms.rnd.fld2 get]"		;# random seed value
5296	puts $fd "Trail	[$x.sms.int.fld4 get]"		;# error trail name
5297	puts $fd "SkipStep	[$x.sms.skp.ent get]"	;# steps skipped
5298	puts $fd "MaxStep	[$x.sms.ub.ent get]"	;# max steps
5299	puts $fd "VarVals	$var_vals"		;# variable values
5300	puts $fd "FullQ	$l_typ"				;# block/loses choice
5301	puts $fd "MSC_Full	$msc_full"		;# MSC+stmnt boolean
5302	puts $fd "MaxText	[$x.afq.max.me get]"	;# MSC max text width
5303	puts $fd "Delay	[$x.afq.delay.me get]"		;# MSC update delay
5304	puts $fd "Pids	[$x.filters.pids.ent get]"	;# process ids
5305	puts $fd "Qids	[$x.filters.qids.ent get]"	;# queue ids
5306	puts $fd "Vars	[$x.filters.vars.ent get]"	;# var names
5307	puts $fd "Track	[$x.filters.track.ent get]"	;# tracked var
5308	puts $fd "Scale	[$x.filters.scale.ent get]"	;# track scaling
5309
5310	dump_contents "Data"   $fd $vwin
5311	dump_contents "Sim"    $fd $swin
5312	dump_contents "Queues" $fd $qwin
5313
5314# LTL
5315global nvr_pan note_pan sym_pan ltl_main
5316global negate_ltl
5317
5318	puts $fd "LTL_Panel	$LTL_Panel"
5319
5320	if {$LTL_Panel} {
5321		# PM width/height of symbol/notes/claim/log panels
5322
5323		puts $fd "Formula	[$ltl_main.left.frm.ent get]"
5324		puts $fd "Template	[$ltl_main.left.frm.tmp get]"
5325		puts $fd "All	$negate_ltl"	;# all/no executions
5326
5327		dump_contents "Symbols" $fd $sym_pan
5328		dump_contents "Notes" $fd $note_pan
5329		dump_contents "Claim" $fd $nvr_pan
5330	}
5331
5332# Verification
5333	# PM width/height of ref and output panels
5334
5335global p_mode a_mode e_mode x_mode f_mode s_mode q_mode
5336global cc_mode ma_mode c_mode estop bf_mode po_mode
5337global bc_mode it_mode u_mode sv_mode peg vranges
5338global vpanel vo V_Panel_3
5339
5340	puts $fd "a_mode	$a_mode"
5341	puts $fd "bc_mode	$bc_mode"
5342	puts $fd "bc_bound	[$vpanel.top.third.rowB.ent get]"
5343	puts $fd "bf_mode	$bf_mode"
5344	puts $fd "c_mode	$c_mode"
5345	puts $fd "cc_mode	$cc_mode"
5346	puts $fd "e_mode	$e_mode"
5347	puts $fd "estop		$estop"
5348	puts $fd "f_mode	$f_mode"
5349	puts $fd "it_mode	$it_mode"
5350	puts $fd "ma_mode	$ma_mode"
5351	puts $fd "p_mode	$p_mode"
5352	puts $fd "peg		$peg"
5353	puts $fd "po_mode	$po_mode"
5354	puts $fd "q_mode	$q_mode"
5355	puts $fd "s_mode	$s_mode"
5356	puts $fd "sv_mode	$sv_mode"
5357	puts $fd "u_mode	$u_mode"
5358	puts $fd "vranges	$vranges"
5359	puts $fd "x_mode	$x_mode"
5360
5361	if {$V_Panel_3} {
5362		puts $fd "vrow0		[$vpanel.top.right.row0.ent get]"	;# phys mem
5363		puts $fd "vrow1		[$vpanel.top.right.row1.ent get]"	;# state space size
5364		puts $fd "vrow2		[$vpanel.top.right.row2.ent get]"	;# max depth
5365		puts $fd "vrow3		[$vpanel.top.right.row3.ent get]"	;# nr hashfcts
5366		puts $fd "vrow4		[$vpanel.top.right.row4.ent get]"	;# MA size
5367		puts $fd "vrow5		[$vpanel.top.right.row5.ent get]"	;# extra spin options
5368		puts $fd "vrow6		[$vpanel.top.right.row6.ent get]"	;# extra cc options
5369		puts $fd "vrow7		[$vpanel.top.right.row7.ent get]"	;# extra pan options
5370	}
5371	dump_contents "VerOut" $fd $vo
5372
5373# Swarm
5374global spanel so sr
5375	# PM height setup and output panels
5376
5377	puts $fd "srow0 	[$spanel.top.left.row0.e0 get]"	;# min hashfcts
5378	puts $fd "srow1 	[$spanel.top.left.row1.e0 get]"	;# max hashfcts
5379	puts $fd "srow2 	[$spanel.top.left.row2.e0 get]"	;# min search depth
5380	puts $fd "srow3 	[$spanel.top.left.row3.e0 get]"	;# max search depth
5381	puts $fd "srow4 	[$spanel.top.left.row4.e0 get]"	;# nr cpus local
5382	puts $fd "srow5 	[$spanel.top.left.row5.e0 get]"	;# nr cpus remote
5383	puts $fd "srow6 	[$spanel.top.left.row6.e0 get]"	;# max mem per run
5384	puts $fd "srow7 	[$spanel.top.left.row7.e0 get]"	;# max runtime
5385
5386	puts $fd "srow8 	[$spanel.top.middle.row8.e1 get]"	;# hash-factor
5387	puts $fd "srow9 	[$spanel.top.middle.row9.e1 get]"	;# statevector size in bytes
5388	puts $fd "srow10	[$spanel.top.middle.row10.e1 get]"	;# exploration speed
5389
5390	puts $fd "srow11	[$spanel.top.middle.row11.e1 get]"	;# extra spin args
5391	puts $fd "srow12	[$spanel.top.middle.row12.e1 get]"	;# extra pan args
5392
5393	dump_contents "CCopts"  $fd $spanel.top.right.row0	;# compilation options
5394	dump_contents "SwSetup" $fd $so		;# contents setup output panel?
5395	dump_contents "SwRun"   $fd $sr		;# contents swarm output panel?
5396
5397	catch "close $fd"
5398	add_log "session save in $Sname" 1
5399}
5400
5401proc save_spec {n} {
5402	global Fname twin
5403
5404	set f $Fname
5405	if {$n == 1} { set f [tk_getSaveFile] }
5406	if {$f != ""} { writeoutfile $f }
5407}
5408
5409proc save_ltl {t} {
5410	global sym_pan note_pan nvr_pan
5411
5412	if {[$t.left.frm.ent get] == ""} {
5413		ltl_log "error: save, no formula specified"
5414		return
5415	}
5416	gen_claim $t.left.frm.ent $nvr_pan $sym_pan	;# needed for negations
5417
5418	switch -- [set file [eval tk_getSaveFile -initialdir { [pwd] } ]] "" {
5419		ltl_log "error: file select failed"
5420		return
5421	}
5422	if ![file_ok $file] {
5423		ltl_log "error: save, '$file' is not writable"
5424		return
5425	}
5426
5427	if [catch {set fd [open $file w]} errmsg] { return }
5428
5429	puts $fd [string trimright [ $sym_pan get 0.0 end] "\n"]
5430
5431	puts $fd [string trimright "	/*\n"]
5432	puts $fd [string trimright "	* Formula As Typed: [$t.left.frm.ent get]\n"]
5433	puts $fd [string trimright "	*/\n"]
5434	puts $fd [string trimright [ $nvr_pan get 0.0 end] "\n"]
5435
5436	puts $fd [string trimright "#ifdef NOTES\n"]
5437	puts $fd [string trimright [ $note_pan get 0.0 end] "\n"]
5438	puts $fd [string trimright "#endif\n"]
5439
5440	close $fd
5441
5442	put_t_name $t $file
5443	ltl_log "saved in '[$t.left.frm.tmp get]'"
5444}
5445
5446proc load_from {t file} {
5447	global negate_ltl sym_pan nvr_pan note_pan
5448
5449	if [catch {set fd [open $file r]} errmsg] {
5450		ltl_log "error: cannot open '$file'"
5451		return
5452	}
5453
5454	clear_ltl $t
5455	put_t_name $t $file
5456
5457	set inside_claim 0
5458	set inside_notes 0
5459	while {[gets $fd line] > -1} {
5460		if {$inside_claim} {
5461			$nvr_pan insert end $line\n
5462			if {[string first "\}" $line] == 0} {
5463				set inside_claim 0
5464			}
5465			continue
5466		}
5467		if {$inside_notes} {
5468			if {[string first "#endif" $line] == 0} {
5469				set inside_notes 0
5470				continue
5471			}
5472			$note_pan insert end $line\n
5473			continue
5474		}
5475		if {[string first "#define" $line] >= 0} {
5476			$sym_pan insert end $line\n
5477			continue
5478		}
5479		if {[string first "* Formula As Typed: " $line] > 0} {
5480			set sof [string first ":" $line]
5481			incr sof 2
5482			$t.left.frm.ent insert end [string range $line	$sof end]
5483			continue
5484		}
5485		if {[string first "never" $line] == 0} {
5486			set inside_claim 1
5487			if {[string first "/* !(" $line] > 0} {
5488				set negate_ltl 1
5489			}
5490			$nvr_pan insert end $line\n
5491			continue
5492		}
5493		if {[string first "#ifdef NOTES" $line] >= 0} {
5494			set inside_notes 1
5495		}
5496		if {[string first "#ifdef RESULT" $line] >= 0} {
5497			set inside_notes 1
5498			$note_pan insert end "==Verification Result===\n"
5499		}
5500	}
5501
5502	catch " close $fd "
5503	ltl_log "load '$file'"
5504}
5505
5506proc load_ltl {t} {
5507
5508	set ftypes {
5509		{{Spin LTL template format} {.ltl} }
5510		{{All Files}	*}
5511	}
5512	switch -- [set file [tk_getOpenFile -filetypes $ftypes]] "" return
5513
5514	load_from $t $file
5515}
5516
5517proc reopen_ltl {t} {
5518	load_from $t [$t.left.frm.tmp get]
5519}
5520
5521proc ltl_panel {t} {
5522	global NBG NFG TBG TFG CBG CFG LTLbg HV0 HV1 negate_ltl ltl_main
5523	global sym_pan note_pan nvr_pan log_pan ScrollBarSize Fname
5524
5525	set ltl_main $t
5526	$t configure -background $LTLbg
5527
5528	frame $t.left
5529	pack $t.left -side top -fill both -expand yes
5530
5531	frame $t.left.frm -bg $TBG
5532	label $t.left.frm.lbl -text "LTL Formula:" -bg $TBG -fg $TFG -font $HV1
5533	entry $t.left.frm.ent -width 60 -relief sunken
5534	label $t.left.frm.tnm -text "Template File:" -bg $TBG -fg $TFG
5535	entry $t.left.frm.tmp -width 30 -relief sunken -bg white -fg $TFG
5536	button $t.left.frm.browse -text "browse" -command "load_ltl $t" \
5537		-relief raised -bg $TBG -fg $TFG
5538	$t.left.frm.tmp insert insert "(use save/load)"
5539
5540	set et $t.left.frm.ent
5541
5542	frame $t.left.op -bg $TBG
5543	pack  $t.left.op -side top -fill x -expand no
5544	set alw {\[\] }
5545	set eve {\<\> }
5546	pack [label $t.left.op.s0 -text "Valid Operators: " -bg $TBG -fg $TFG -relief flat] -side left
5547	pack [button $t.left.op.always -bg $CBG -fg $CFG -font $HV0 -text " always: \[\] " \
5548		-command "$et insert insert \"$alw \""] -side left
5549	pack [button $t.left.op.event -bg $CBG -fg $CFG -font $HV0 -text " eventually: \<\> " \
5550		-command "$et insert insert \"$eve \""] -side left
5551	pack [button $t.left.op.until -bg $CBG -fg $CFG -font $HV0 -text " strong-until: U " \
5552		-command "$et insert insert \" U \""] -side left
5553	pack [button $t.left.op.impl -bg $CBG -fg $CFG -font $HV0 -text " implication: -> " \
5554		-command "$et insert insert \" -> \""] -side left
5555	pack [button $t.left.op.and -bg $CBG -fg $CFG -font $HV0 -text " and: && " \
5556		-command "$et insert insert \" && \""] -side left
5557	pack [button $t.left.op.or -bg $CBG -fg $CFG -font $HV0 -text " or: || " \
5558		-command "$et insert insert \" || \""] -side left
5559	pack [button $t.left.op.not -bg $CBG -fg $CFG -font $HV0 -text "negation: ! " \
5560		-command "$et insert insert \" ! \""] -side left
5561
5562	button $t.left.op.open -text "ReLoad" -command "reopen_ltl $t" \
5563		-activebackground $NFG -activeforeground $NBG \
5564		-relief raised -bg $NBG -fg $NFG -font $HV0
5565	button $t.left.op.save -text "Save as"  -command "save_ltl $t" \
5566		-activebackground $NFG -activeforeground $NBG \
5567		-relief raised -bg $NBG -fg $NFG -font $HV0
5568	button $t.left.op.clear -text "Clear"   -command "clear_ltl $t" \
5569		-activebackground $NFG -activeforeground $NBG \
5570		-relief raised -bg $NBG -fg $NFG -font $HV0
5571	button $t.left.op.help -text "Help"   -command "help_ltl" \
5572		-activebackground $NFG -activeforeground $NBG \
5573		-relief raised -bg $NBG -fg $NFG -font $HV0
5574
5575	pack $t.left.op.help $t.left.op.clear $t.left.op.save $t.left.op.open \
5576		-side right -fill x -expand no
5577	pack $t.left.frm.lbl $t.left.frm.ent \
5578		-side left -fill x -expand no
5579	pack $t.left.frm.browse $t.left.frm.tmp $t.left.frm.tnm \
5580		-side right -fill x -expand no
5581	pack $t.left.frm -fill x -expand no
5582
5583	frame $t.left.hlds -bg $TBG
5584	label $t.left.hlds.nm -text "Property holds for:" -bg $TBG -fg $TFG
5585	radiobutton $t.left.hlds.yes -text "all executions (expresses desired behavior)" \
5586		-variable negate_ltl -value 0 -bg $TBG -fg $TFG
5587	radiobutton $t.left.hlds.non -text "no executions (expresses error behavior)" \
5588		-variable negate_ltl -value 1 -bg $TBG -fg $TFG
5589
5590	pack $t.left.hlds -side top -fill x -expand no
5591	pack $t.left.hlds.nm $t.left.hlds.yes $t.left.hlds.non \
5592		-side left -fill x -expand no
5593
5594	label $t.left.spacer1 -height 1 -bg $LTLbg
5595	pack  $t.left.spacer1 -side top -fill x -expand no
5596###
5597	set horiz_pw [PanedWindow $t.left.top -side top -activator button ]
5598	set lft    [$horiz_pw add]	;# left hand side
5599	set rgt    [$horiz_pw add]	;# right hand side
5600	pack $horiz_pw -fill both -expand yes
5601
5602	set ltl_pw  [PanedWindow $lft.x -side left -activator button ]
5603	set mp      [$ltl_pw add]	;# macros
5604	set np      [$ltl_pw add]	;# notes
5605	set cp      [$ltl_pw add]	;# claim
5606
5607	set not_pw  [PanedWindow $rgt.x -side left -activator button ]
5608	set lp      [$not_pw add]	;# log
5609	pack $ltl_pw $not_pw -fill both -expand yes
5610### Macros
5611	set mp_t    [label $mp.t -text "Symbol macro-definitions (all symbols used in formula):" \
5612		-bg $TBG -fg $TFG -font $HV0]
5613	set sw1     [ScrolledWindow $mp.sw1 -size $ScrollBarSize]
5614	set sym_pan [text $sw1.lb -height 4 -font $HV1]
5615	$sw1 setwidget $sym_pan
5616### Notes
5617	set np_t    [label $np.n -text "Notes (informal explanation of property):" \
5618		-bg $TBG -fg $TFG -font $HV0]
5619	set sw3     [ScrolledWindow $np.sw3 -size $ScrollBarSize]
5620	set note_pan [text $sw3.lb -height 4 -font $HV1]
5621	$sw3 setwidget $note_pan
5622### Claim
5623	set cp_t    [button $cp.n -text "Never Claim (click to generate):" \
5624		-bg $TBG -fg $TFG -font $HV0]
5625	set sw5     [ScrolledWindow $cp.sw5 -size $ScrollBarSize]
5626	set nvr_pan [text $sw5.lb -height 4 -font $HV1]
5627	$sw5 setwidget $nvr_pan
5628	$cp.n configure -command "gen_claim $et $nvr_pan $sym_pan"
5629### Log
5630	set sw7     [ScrolledWindow $lp.sw7 -size $ScrollBarSize]
5631	set log_pan [text $sw7.lb -width 60 -relief sunken -bg $CBG -fg $CFG -font $HV1]
5632	$sw7 setwidget $log_pan
5633
5634	pack $mp_t -fill x -expand no
5635	pack $sw1 -fill both -expand yes
5636
5637	pack $np_t -fill x -expand no
5638	pack $sw3 -fill both -expand yes
5639
5640	pack $cp_t -fill x -expand no
5641	pack $sw5 -fill both -expand yes
5642
5643	pack $sw7 -fill both -expand yes
5644
5645	bind $et <Return> " gen_claim $et $nvr_pan $sym_pan"
5646
5647	ltl_log "ltl log"
5648}
5649
5650set scrollxregion 10000
5651set scrollyregion 40000
5652
5653proc simulate_panel {t} {
5654	global x CBG CFG HV0 HV1 ScrollBarSize scrollxregion scrollyregion
5655	global s_typ seed skipstep ubstep l_typ var_vals
5656	global TBG TFG NBG NFG XBB Fname msc_max_w msc_delay
5657	global rwin swin cwin vwin qwin msc msc_full
5658
5659	set pws  [PanedWindow $t.pw -side left -activator button ]
5660
5661	set p2  [$pws add -minsize 10]
5662	set p1  [$pws add -minsize 10]
5663
5664	set sf1    [ScrolledWindow $p1.sw -size $ScrollBarSize]
5665	set tbot   [text $sf1.lb -highlightthickness 0 -bg $CBG -fg $CFG -font $HV1]
5666	$sf1 setwidget $tbot
5667
5668	set ttop [frame $p2.sw ]	;# we create the ref scrolled text window below
5669	set sf2 $ttop
5670
5671	pack $sf1 $sf2 $pws -fill both -expand yes
5672
5673#### Simulation Mode
5674	set topf  [frame $ttop.topf]
5675	pack $topf -pady 2 -side top -fill both -expand yes
5676
5677	frame $topf.left -bg $TBG	;# left side of top frame; there's no right side yet
5678	pack $topf.left -side top -fill both -expand no
5679
5680	set x $topf.left
5681	frame $x.sms -bg $TBG
5682	label $x.sms.fld0 -text "Mode" -relief raised -bg $TBG -fg $TFG
5683
5684	pack $x.sms -padx 1 -pady 1 -side left -fill both -expand no
5685	pack $x.sms.fld0 -side top -fill x -expand no
5686
5687#### Reference Model for Tracking
5688	set mws [PanedWindow $topf.middle -side top -activator button ]
5689
5690	set q0 [$mws add -minsize 10]
5691	set q1 [$mws add -minsize 10]
5692
5693	# bottom part of top frame: model text for tracking
5694	set ref    [ScrolledWindow $q0.middle -size $ScrollBarSize]
5695	set rwin   [text $ref.lb -highlightthickness 0 -font $HV1]
5696	$ref setwidget $rwin
5697	pack $ref -side left -fill both -expand yes
5698
5699	$rwin insert end "reference to model source $Fname"
5700
5701	set cref   [ScrolledWindow $q1.middle -size $ScrollBarSize]
5702	set msc    [canvas $cref.right -relief raised \
5703		-background $XBB -scrollregion "0 0 $scrollxregion $scrollyregion" ]
5704	$cref setwidget $msc
5705
5706	pack $mws -side top -fill both -expand yes
5707	pack $cref -side right -fill both -expand yes
5708
5709	$msc create text 20 10 -text "MSC $msc_full" -fill white
5710
5711	bind  $rwin <KeyRelease> {
5712		if {"%K" == "Return"} {
5713			$rwin insert insert "[$rwin index insert]	"
5714			$rwin edit modified true
5715	}	}
5716
5717	bind $msc <2> "$msc scan mark %x %y"
5718	bind $msc <B2-Motion> "$msc scan dragto %x %y"
5719
5720
5721#### Random
5722	frame $x.sms.rnd -bg $TBG
5723	radiobutton $x.sms.rnd.fld1 -text "Random, with seed: " \
5724		-variable s_typ -value 0 -bg $TBG -fg $TFG
5725	entry       $x.sms.rnd.fld2 -relief sunken -width 12
5726
5727	pack $x.sms.rnd -side top -fill x -expand no
5728	pack $x.sms.rnd.fld1 -side left -fill x -expand no
5729	pack $x.sms.rnd.fld2 -side right -fill x -expand no
5730
5731	$x.sms.rnd.fld2 insert end $seed
5732
5733### Interactive
5734	frame $x.sms.usr -bg $TBG
5735	radiobutton $x.sms.usr.fld -text "Interactive (for resolution of all nondeterminism)" \
5736		-variable s_typ -value 2 -bg $TBG -fg $TFG
5737	pack $x.sms.usr -side top -fill x -expand no
5738	pack $x.sms.usr.fld -side left -fill x -expand no
5739
5740#### Guided
5741	frame $x.sms.int -bg $TBG
5742	radiobutton $x.sms.int.fld3 -text "Guided, with trail:" \
5743		-variable s_typ -value 1 -bg $TBG -fg $TFG
5744	entry       $x.sms.int.fld4 -relief sunken
5745	button      $x.sms.int.fld5 -relief raised -text "browse" \
5746		-command { find_trail $x.sms.int.fld4 } -bg $TBG -fg $TFG
5747
5748	pack $x.sms.int -side top -fill x -expand no
5749	pack $x.sms.int.fld3 -side left -fill x -expand no
5750	pack $x.sms.int.fld4 -side left -fill x -expand no
5751	pack $x.sms.int.fld5 -side left -fill x -expand no
5752
5753#### Initial Steps
5754	frame $x.sms.skp -bg $TBG
5755	label $x.sms.skp.lbl -text "  initial steps skipped:" -bg $TBG -fg $TFG
5756	entry $x.sms.skp.ent -relief sunken -width 12
5757
5758	$x.sms.skp.ent insert end $skipstep
5759
5760	frame $x.sms.ub -bg $TBG
5761	label $x.sms.ub.lbl -text "  maximum number of steps:" -bg $TBG -fg $TFG
5762	entry $x.sms.ub.ent -relief sunken -width 12
5763		$x.sms.ub.ent insert end $ubstep
5764
5765	frame $x.sms.vv -bg $TBG
5766		checkbutton $x.sms.vv.xx -variable var_vals \
5767		-text "Track Data Values (this can be slow)" -bg $TBG -fg $TFG
5768
5769	pack $x.sms.skp -side top -fill x -expand no
5770		pack $x.sms.skp.lbl -side left  -fill x -expand no
5771		pack $x.sms.skp.ent -side right -fill x -expand no
5772
5773	pack $x.sms.ub  -side top -fill x -expand no
5774		pack $x.sms.ub.lbl -side left -fill x -expand no
5775		pack $x.sms.ub.ent -side right -fill x -expand no
5776
5777	pack $x.sms.vv -side top -fill x -expand no
5778		pack $x.sms.vv.xx -side left -fill x -expand no
5779
5780#### A Full Queue
5781	frame $x.afq -bg $TBG
5782	label $x.afq.fld0 -text "A Full Channel" -relief raised -bg $TBG -fg $TFG
5783
5784	pack $x.afq -padx 1 -pady 1 -side left -fill both -expand no
5785	pack $x.afq.fld0 -side top -fill x -expand no
5786#### Blocks/Loses
5787	frame $x.afq.int -bg $TBG
5788		frame $x.afq.int.la -bg $TBG
5789		radiobutton $x.afq.int.la.fld3 -text "blocks new messages" -variable l_typ -value 0 -bg $TBG -fg $TFG
5790		radiobutton $x.afq.int.la.fld4 -text "loses  new messages" -variable l_typ -value 1 -bg $TBG -fg $TFG
5791
5792	pack $x.afq.int -side top -fill x -expand no
5793	pack $x.afq.int.la -side left -fill x -expand yes
5794	pack $x.afq.int.la.fld3 -side top -fill x -expand no -anchor w
5795	pack $x.afq.int.la.fld4 -side top -fill x -expand no -anchor w
5796
5797#### MSC
5798	frame $x.afq.ish -bg $TBG
5799		checkbutton $x.afq.ish.is -text "MSC+stmnt" -variable msc_full -bg $TBG -fg $TFG
5800		pack $x.afq.ish.is -side left -fill x -expand no
5801	pack $x.afq.ish -side top -fill x -expand no
5802
5803	frame $x.afq.max -bg $TBG
5804		label $x.afq.max.mx -text "MSC max text width" -bg $TBG -fg $TFG
5805		entry $x.afq.max.me -relief sunken -width 6
5806		pack $x.afq.max.mx $x.afq.max.me -side left -fill x -expand yes
5807	pack $x.afq.max -side top -fill x -expand no
5808	$x.afq.max.me insert end $msc_max_w
5809
5810	frame $x.afq.delay -bg $TBG
5811		label $x.afq.delay.mx -text "MSC update delay" -bg $TBG -fg $TFG
5812		entry $x.afq.delay.me -relief sunken -width 6
5813		pack $x.afq.delay.mx $x.afq.delay.me -side left -fill x -expand yes
5814	pack $x.afq.delay -side top -fill x -expand no
5815	$x.afq.delay.me insert end $msc_delay
5816
5817
5818#### Output Filters
5819	output_filters $x
5820
5821#### Controls
5822	setup_controls $x
5823
5824#### Command executed
5825	frame $x.bgf -bg $TBG
5826	pack $x.bgf -side right -fill both -expand yes
5827	set lwin [label $x.bgf.lbl -text "Background command executed:" -bg $TBG -fg $TFG]
5828	pack $lwin -side top -fill x -expand no
5829	set cwin [text $x.bgf.cmd -height 6 -bg lightgray -fg $TFG -font $HV1]
5830	pack $cwin -side top -fill both -expand yes
5831	button $x.bgf.ps -text "Save in: msc.ps" -font $HV0 \
5832		-fg black -bg ivory -activeforeground $NBG -activebackground $NFG \
5833		-command "$msc postscript -file msc.ps -colormode color"
5834	pack $x.bgf.ps -side right -expand no
5835
5836### Simulation output
5837	set bwp  [PanedWindow $tbot.pw -side top -activator button ]
5838
5839	set p2  [$bwp add -minsize 10]
5840	set p1  [$bwp add -minsize 10]
5841	set p0  [$bwp add -minsize 10]
5842
5843	set lwp    [ScrolledWindow $p1.sw -size $ScrollBarSize]
5844	set swin   [text $lwp.lb -highlightthickness 0 -bg $CBG -fg $CFG -font $HV1]
5845	$lwp setwidget $swin
5846
5847	pack $lwp $bwp -fill both -expand yes
5848
5849	$swin insert end "Simulation output"
5850
5851### Data Values
5852	set si3    [ScrolledWindow $p2.sw2 -size $ScrollBarSize]
5853	set vwin   [text $si3.lb -width 20 -highlightthickness 0 -bg $CBG -fg $CFG]
5854	$si3 setwidget $vwin
5855
5856	pack $si3 -side right -fill both -expand yes
5857	$vwin insert end "Data Values"
5858
5859	set si4    [ScrolledWindow $p0.sw0 -size $ScrollBarSize]
5860	set qwin   [text $si4.qv -width 20 -highlightthickness 0 -bg $CBG -fg $CFG]
5861	$si4 setwidget $qwin
5862
5863	pack $si4 -side top -fill both -expand yes
5864	$qwin insert end "Queues"
5865}
5866
5867proc curp { x } {
5868	global Curp rwin vr
5869
5870	if {$Curp == "Sp"} {
5871		update_master $rwin
5872	}
5873	if {$Curp == "Vp"} {
5874		update_master $vr
5875	}
5876
5877	set Curp $x
5878}
5879
5880proc create_panels {} {
5881	global Curp NBG NFG MFG MBG version xversion HV0 Fname tcl_platform
5882	global LTL_Panel
5883
5884	frame .menu -bg $MFG
5885	label .menu.title -text "$version :: $xversion" -bg $MFG -fg $MBG	;# reversed menu colors
5886	pack append .menu .menu.title {left frame c expand}
5887	pack append . .menu {top frame w fillx}
5888
5889	set pane .f
5890	set nb [NoteBook $pane -bg $NBG -fg $NFG -font $HV0 \
5891		-activebackground $NFG -activeforeground $NBG -side top]
5892
5893	pack $pane -fill both -expand yes
5894
5895	model_panel    [$nb insert end Mp -text " Edit/View "         -raisecmd "curp Mp" ]
5896	simulate_panel [$nb insert end Sp -text " Simulate / Replay " -raisecmd "curp Sp; runsim" ]
5897
5898	if {$LTL_Panel} {
5899	ltl_panel      [$nb insert end Lp -text " LTL Properties "    -raisecmd "curp Lp; runltl" ]
5900	}
5901	verify_panel   [$nb insert end Vp -text " Verification "      -raisecmd "curp Vp; runveri" ]
5902	swarm_panel    [$nb insert end Sw -text " Swarm Run "         -raisecmd "curp Sw; runswarm" ]
5903
5904	$nb insert end Hp -text " <Help> "          -raisecmd "helper; $pane raise $Curp"
5905	$nb insert end Ss -text " Save Session "    -raisecmd "save_session 1;  $pane raise $Curp"
5906	$nb insert end Rs -text " Restore Session " -raisecmd "restore_session; $pane raise $Curp"
5907	$nb insert end Qt -text " <Quit> "          -raisecmd "cleanup; checked_exit; $pane raise $Curp"
5908
5909	$pane raise Mp	;# default view
5910}
5911
5912proc runltl   {} { add_log "ltl property" 1 }
5913proc runswarm {} { add_log "swarm run" 1 }
5914
5915proc runsim {} {
5916	global rwin s_typ Fname
5917
5918	update_ref $rwin
5919	add_log "simulate/replay" 1
5920
5921	if {[catch { set fd [open "$Fname.trail" r]} errmsg]} {
5922		;# no trail file
5923	} else {
5924		catch { close $fd }
5925		set s_typ 1
5926	}
5927}
5928proc runveri {} {
5929	global vr p_mode
5930
5931	update_ref $vr
5932	add_log "verification" 1
5933
5934	if {[has_label "accept" ""]} {
5935		set p_mode 2		;# liveness
5936	} else {
5937		if {[has_label "progress" ""]} {
5938			set p_mode 1	;# liveness
5939		} else {
5940			set p_mode 0	;# safety
5941	}	}
5942
5943}
5944
5945
5946proc bind_lines {into rf} {
5947	global SFG CFG Fname pane
5948
5949	set cnt 0
5950	scan [$into index end] %d numLines
5951	for {set i 1} {$i <= $numLines} { incr i} {
5952		set line [$into get $i.0 $i.end]
5953		set matched ""
5954		regexp {[A-Za-z0-9_\.]+:[0-9]+} $line matched
5955		if {$matched == ""} { continue }
5956
5957		set fn [string first $matched $line]
5958		set char $fn
5959		set fn $i.$fn
5960		incr char [string length $matched]
5961		set splitx [split $matched ":"]
5962		set fnm [lindex $splitx 0]
5963		set lnr [lindex $splitx 1]
5964
5965		set indend $i
5966		append indend "." $char
5967
5968		$into tag add hilite$cnt $fn $indend
5969		$into tag bind hilite$cnt <ButtonPress-1> "
5970			if {\[string compare \"$fnm\" \$Fname] == 0 || \[readinfile \"$fnm\" \]} {
5971				$rf yview -pickplace $lnr.0
5972				catch { $rf tag delete hilite }
5973				$rf tag add hilite $lnr.0 $lnr.end
5974				$rf tag configure hilite -foreground $SFG
5975			}
5976		"
5977		$into tag bind hilite$cnt <Enter> "
5978			$into tag configure hilite$cnt -foreground $SFG
5979		"
5980		$into tag bind hilite$cnt <Leave> "
5981			$into tag configure hilite$cnt -foreground $CFG
5982		"
5983		incr cnt
5984	}
5985}
5986
5987proc queue_update {n} {	;# in separate panel from vars
5988	global QStep Qnm Levels qwin
5989
5990	if { [info exists Levels($n)] == 0 } {
5991		set Levels($n) "-"
5992	}
5993
5994	$qwin delete 0.0 end
5995	$qwin insert end "\[queues, step $Levels($n)\]\n\n"
5996	foreach el [lsort [array names Qnm]] {
5997		catch {
5998			set qc $QStep([list $n $el])
5999		#	set ff [string last ":" $qc]
6000		#	incr ff
6001		#	set cargo [string range $qc $ff end]
6002
6003			set ff [string first "(" $qc]
6004			set cargo [string range $qc $ff end]
6005
6006			$qwin insert end "q $el :: $cargo\n"
6007	}	}
6008}
6009
6010proc step_forw {} {
6011	global curn maxn
6012
6013	if {$curn >= $maxn} { return }
6014	incr curn
6015	var_update $curn
6016	queue_update $curn
6017}
6018
6019proc step_back {} {
6020	global curn maxn
6021
6022	if {$curn <= 1} { return }
6023	incr curn -1
6024	var_update $curn
6025	queue_update $curn
6026}
6027
6028proc rewind {} {
6029	global curn x msc
6030
6031	set curn 1
6032	var_update $curn
6033	queue_update $curn
6034	catch {
6035		$x.run.ctl.step  configure -fg gold -command step_forw
6036		$x.run.ctl.back  configure -fg gold -command step_back
6037	}
6038	$msc yview moveto 0.0
6039}
6040
6041set ostep 0
6042
6043proc var_update {n} {
6044	global VarStep Varnm swin vwin Levels curn maxn LineNo
6045	global MSC_Y msc msc_w msc_h msc_max_x ostep SFG CFG NFG
6046
6047	set curn $n
6048
6049	if { [info exists Levels($n)] == 0 || $Levels($n) == "-" } {
6050		return
6051	#	set Levels($n) "0"
6052	}
6053
6054	$vwin delete 0.0 end
6055	$vwin insert end "\[variable values, step $Levels($n)\]\n\n"
6056	foreach el [lsort [array names Varnm]] {
6057		catch { $vwin insert end " $el = $VarStep([list $n $el])\n" }
6058	}
6059
6060	set showln [expr $LineNo($n) - 1]
6061	if {$showln <= 0} {
6062		return
6063	#	set showln 0
6064	}
6065	$swin yview -pickplace $showln
6066
6067	# find closest entry in MSC_Y not larger than lookfor
6068	set lookfor $Levels($n)
6069	set putithere	0
6070	foreach el [array names MSC_Y] {
6071		if {$el < $lookfor} {
6072			if {$el > $putithere} {
6073				set putithere $el
6074	}	}	}
6075
6076	$msc delete wherearewe
6077	if {[info exists MSC_Y($putithere)] == 0} {
6078		set MSC_Y($putithere) 0		;# really $msc_min_y - $msc_h
6079	}
6080	set ty [expr $MSC_Y($putithere) + $msc_h]
6081	$msc create line \
6082		30 $ty \
6083		[expr $msc_max_x + $msc_w] $ty \
6084		-width 1 -dash {8 2} -fill red -tags wherearewe
6085
6086	# highlight line in text view:
6087	catch { $swin tag configure bound$ostep -foreground $CFG }
6088	$swin tag configure bound$n -foreground $NFG
6089	set ostep $n
6090}
6091
6092proc file_view {fnm zzz} {
6093	global Fname SFG rwin
6094
6095	if {$fnm != ""} {
6096		if {[string compare "$fnm" $Fname] == 0 || [readinfile "$fnm" ]} {
6097			$rwin yview -pickplace $zzz.0
6098			catch { $rwin tag delete hilite }
6099			$rwin tag add hilite $zzz.0 $zzz.end
6100			$rwin tag configure hilite -foreground $SFG
6101			$rwin yview -pickplace [expr $zzz - 5]
6102	}	}
6103}
6104
6105proc put_msc {how sno prno stmnt ss pnm fnm zzz} {
6106	global msc msc_x msc_y msc_w msc_h msc_max_x scrollyregion
6107	global x ProcessLine MSC_Y msc_max_w msc_delay HV0 CBG NFG
6108	global XBG XFG XTX XAR XPR
6109
6110	if {$msc_max_x < $msc_x} {
6111		set msc_max_x $msc_x
6112	}
6113
6114	set msc_max_w [$x.afq.max.me get]
6115	set mw [font measure $HV0 "w"]
6116	set mw [expr $mw * $msc_max_w]
6117	set msc_x [expr ($mw / 2) + $prno * ($msc_w + 10)]
6118
6119	set dx [expr $msc_x + $msc_w / 2 ]
6120	if {[info exists ProcessLine($prno)]} {
6121		$msc create line \
6122			$dx $ProcessLine($prno) \
6123			$dx $msc_y -tags session \
6124			-width 1 -fill $XPR
6125	} else {
6126		$msc create text \
6127			$dx [expr $msc_y - $msc_h / 2] \
6128			-text "$pnm:$prno" -fill $XTX -tags session
6129	}
6130	set ProcessLine($prno) [expr $msc_y + $msc_h]
6131
6132	set MSC_Y($sno) $msc_y
6133
6134	if {$how} {
6135		$msc create rectangle \
6136			$msc_x $msc_y \
6137			[expr $msc_x + $msc_w] [expr $msc_y + $msc_h] \
6138			-outline $XBG -fill $XFG -tags session
6139		set tcol $XTX
6140	} else {
6141		set tcol black
6142	}
6143	set stmnt [string trimleft $stmnt "\["]
6144	set stmnt [string trimright $stmnt "\]"]
6145
6146	if {[string length $stmnt] > $msc_max_w} {
6147		set stmnt [string range $stmnt 0 $msc_max_w]
6148		set stmnt "$stmnt..."
6149	}
6150
6151	set nv [$msc create text \
6152		[expr $msc_x + $msc_w / 2] [expr $msc_y + $msc_h / 2] \
6153		-text "$stmnt" -font $HV0 -fill $tcol -tags session]
6154
6155	$msc bind $nv <ButtonPress-1> "
6156		var_update $ss
6157		queue_update $ss
6158		file_view {$fnm} $zzz
6159	"
6160
6161	$msc create text \
6162		15 [expr $msc_y + $msc_h / 2] \
6163		-text "$sno" -fill $XTX -tags sno	;# sno: step number
6164
6165	catch " $msc yview moveto [expr 1.0 * ($msc_y - 10*$msc_h) / $scrollyregion] "
6166	update
6167
6168	set msc_delay [$x.afq.delay.me get]
6169	if {$msc_delay > 0} {
6170		after $msc_delay
6171	}
6172}
6173
6174proc handle_ipc {qno istype} {
6175	global Qfill Qempty Mbox_x Mbox_y XAR
6176	global msc msc_x msc_y msc_w msc_h
6177
6178	## connect send to receive
6179	## just deals with the easy case
6180	## so far, ie not !! or ??
6181
6182	if {[info exists Qfill($qno)] == 0} {
6183		set Qfill($qno)  1
6184		set Qempty($qno) 1
6185	}
6186
6187	if {$istype == 1} {	;# send
6188		set Mbox_x([list $Qfill($qno) $qno]) $msc_x
6189		set Mbox_y([list $Qfill($qno) $qno]) [expr $msc_y + $msc_h / 2]
6190		incr Qfill($qno)
6191	} else {		;# recv
6192		set ox $Mbox_x([list $Qempty($qno) $qno])
6193		set oy $Mbox_y([list $Qempty($qno) $qno])
6194		set tx $msc_x
6195		set ty [expr $msc_y + $msc_h / 2]
6196
6197		if {$oy != 0 && $oy != 0} {
6198			if {$ox < $tx} {
6199				incr ox $msc_w
6200			} else {
6201				incr tx $msc_w
6202			}
6203## -dash { 4 2 } -width 3
6204			$msc create line $ox $oy $tx $ty -width 1 \
6205				-fill $XAR -arrow last -arrowshape {3 5 3} -tags session
6206		}
6207		incr Qempty($qno)
6208	}
6209}
6210
6211proc clearup {} {
6212	global Varnm Qnm ProcessLine cwin vwin
6213	global Qfill Qempty Mbox_x Mbox_y
6214
6215	$cwin delete 0.0 end
6216	$vwin delete 0.0 end
6217
6218	catch {
6219		foreach el [array names ProcessLine] {
6220			unset ProcessLine($el)
6221	}	}
6222
6223	catch	{
6224		foreach el [array names Varnm] {
6225			unset Varnm($el)
6226		}
6227		foreach el [array names Qnm] {
6228			unset Qnm($el)
6229	}	}
6230
6231	catch {
6232		foreach el [array names Qfill] {
6233			unset Qfill($el)
6234		}
6235		foreach el [array names Qempty] {
6236			unset Qempty($el)
6237	}	}
6238
6239	catch {
6240		foreach el [array names Mbox_x] {
6241			unset Mbox_x($el)
6242		}
6243		foreach el [array names Mbox_y] {
6244			unset Mbox_y($el)
6245	}	}
6246}
6247
6248proc lines_touched {} {
6249	global LineTouched Fname rwin NBG
6250
6251	foreach el [array names LineTouched] {
6252		set f [lindex $el 0]
6253		if {$f == $Fname} {
6254			set n [lindex $el 1]
6255			$rwin tag add touched $n.0 $n.end
6256	}	}
6257	$rwin tag configure touched -foreground $NBG
6258}
6259
6260proc line_bindings {lnr prno sno line} {
6261	global Levels LineNo step swin SFG CFG msc_full
6262	global Fname rwin step msc_h msc_y LineTouched
6263
6264	set LineNo($step) $lnr
6265	catch { $swin tag remove bound$step 0.0 end }
6266	set ft [string first ":" $line]	;# first colon
6267	set nft [expr $ft - 1]
6268	set Levels($step) [string range $line 0 $nft]
6269
6270	set fnm ""
6271	set zzz 0
6272
6273	set matched ""
6274	regexp {[A-Za-z0-9_\.]+:[0-9]+} $line matched
6275	if {$matched != ""} {
6276		set splitx [split $matched ":"]
6277		set fnm [lindex $splitx 0]
6278		set zzz [lindex $splitx 1]
6279		set LineTouched([list $fnm $zzz]) 1
6280	}
6281
6282	$swin tag add bound$step $lnr.0 $lnr.$ft
6283
6284	if {$matched == ""} {
6285		$swin tag bind bound$step <ButtonPress-1> "
6286			var_update $step
6287			queue_update $step
6288		"
6289	} else {
6290		$swin tag bind bound$step <ButtonPress-1> "
6291			var_update $step
6292			queue_update $step
6293			if {\[string compare \"$fnm\" \$Fname] == 0 || \[readinfile \"$fnm\" \]} {
6294				$rwin yview -pickplace $zzz.0
6295				catch { $rwin tag delete hilite }
6296				$rwin tag add hilite $zzz.0 $zzz.end
6297				$rwin tag configure hilite -foreground $SFG
6298				$rwin yview -pickplace [expr $zzz - 5]
6299			}
6300		"
6301	}
6302	$swin tag bind bound$step <Enter> "
6303		$swin tag configure bound$step -foreground $SFG
6304	"
6305	$swin tag bind bound$step <Leave> "
6306		$swin tag configure bound$step -foreground $CFG
6307	"
6308
6309	if {$msc_full} {
6310		set sos [string first "\[" $line]
6311		if {$sos > 0} {
6312			set stmnt [string range $line $sos end]
6313			if {[string first "!" $stmnt] < 0 \
6314			&&  [string first "?" $stmnt] < 0} {
6315
6316				set a [string first "(" $line]
6317				set b [string first ")" $line]
6318				if {$a > 0 && $b > 0} {
6319					incr a
6320					incr b -1
6321					set c [string range $line $a $b]
6322				} else {
6323					set c "--"
6324				}
6325
6326				put_msc 0 $sno $prno $stmnt $step $c $fnm $zzz
6327				incr msc_y $msc_h
6328	}	}	}
6329}
6330
6331proc var_track {nm vl ts} {
6332	global msc msc_h msc_y o_y o_v
6333
6334	if {$msc_y > $o_y} {
6335		for {set i $o_y} {$i < $msc_y} {incr i $msc_h} {
6336			$msc create line \
6337				30 $i \
6338				[expr 30 + $o_v * $ts] $i \
6339				-width [expr $msc_h - 5] -fill orange -tags vartrack
6340	}	}
6341	set o_y $msc_y
6342	set o_v $vl
6343
6344	$msc create line \
6345		30 $msc_y \
6346		[expr 30 + $vl * $ts] $msc_y \
6347		-width [expr $msc_h - 5] -fill orange -tags vartrack
6348}
6349
6350set Choice(0) ""
6351set PlaceMenu "+150+150"
6352set howmany 0
6353
6354proc pickoption {nm} {
6355	global Choice PlaceMenu howmany NBG NFG cwin swin rwin
6356
6357	set howmany 0
6358	catch {destroy .prompt}
6359	toplevel .prompt
6360	wm title .prompt "Select"
6361	wm iconname .prompt "Select"
6362	wm geometry .prompt $PlaceMenu
6363
6364	text .prompt.t -relief raised -bd 2 \
6365		-width [string length $nm] -height 1 \
6366		-setgrid 1
6367	pack append .prompt .prompt.t { top expand fillx }
6368	.prompt.t insert end "$nm"
6369	set cnt 0
6370	focus .prompt
6371	foreach i [lsort [array names Choice]] {
6372		if {$Choice($i) != 0} {
6373			incr cnt
6374			pack append .prompt \
6375			  [button .prompt.b$cnt -text "$i: $Choice($i)" \
6376			  -anchor w \
6377			  -bg $NBG -fg $NFG \
6378			  -command "set howmany $i" ] \
6379			  {top expand fillx}
6380
6381			set matched ""
6382			regexp {[A-Za-z0-9_\.]+:[0-9]+} $Choice($i) matched
6383			if {$matched == ""} { continue }
6384			set splitx [split $matched ":"]
6385			set fnm [lindex $splitx 0]
6386			set lnr [lindex $splitx 1]
6387			bind .prompt.b$cnt <Enter> "$rwin yview -pickplace $lnr.0"
6388	}	}
6389	pack append .prompt \
6390		[button .prompt.q -text "quit" \
6391		-anchor w -bg $NBG -fg $NFG -command {set howmany "q\n"} ] \
6392		{top expand fillx}
6393
6394	tkwait variable howmany
6395	set PlaceMenu [wm geometry .prompt]
6396	set k [string first "\+" $PlaceMenu]
6397	if {$k > 0} {
6398		set PlaceMenu [string range $PlaceMenu $k end]
6399	}
6400	catch { foreach el [array names Choice]  { unset Choice($el) } }
6401	destroy .prompt
6402	$cwin insert end "$howmany "
6403	$swin insert end "Selected: $howmany\n"
6404	return $howmany
6405}
6406
6407proc run_sim {} {
6408	global stop x swin rwin vwin cwin stop l_typ s_typ Fname SPIN maxn
6409	global VarStep Varnm step QStep Qnm SFG CFG Levels LineNo var_vals
6410	global msc msc_x msc_y msc_w msc_h msc_max_x msc_full MSC_Y Choice
6411
6412	set stop 0
6413	update
6414
6415	set seed    [$x.sms.rnd.fld2 get]
6416	set skipped [$x.sms.skp.ent get]
6417	set upper   [$x.sms.ub.ent get]
6418	set pfilter [$x.filters.pids.ent get]
6419	set vfilter [$x.filters.vars.ent get]
6420	set qfilter [$x.filters.qids.ent get]
6421	set tfilter [$x.filters.track.ent get]
6422	set tscale  [$x.filters.scale.ent get]
6423
6424	if {$tscale == ""} { set tscale 1 }
6425
6426	set args "-p -s -r -X -v -n$seed"
6427
6428	if {$var_vals} { set args "$args -l -g" }
6429
6430	if {$skipped > 0} { set args "$args -j$skipped" }
6431	if {$l_typ != 0}  { set args "$args -m" }
6432	if {$s_typ == 2}  { set args "$args -i" }
6433	if {$s_typ == 1}  {
6434		set tname [$x.sms.int.fld4 get]
6435		if {$tname == ""} {
6436			$cwin insert end "error: no trailfile specified\n"
6437			return
6438		}
6439		if [catch {set fo [open "$tname" r]} errmsg] {
6440			$cwin insert end "$errmsg\n"
6441			return
6442		}
6443		catch { close $fo }
6444
6445		set args "$args -k $tname"
6446	#	set upper 0
6447	}
6448	if {$upper > 0}   { set args "$args -u$upper" }
6449
6450	clearup
6451
6452	set args "$args $Fname"
6453
6454	$cwin insert end "spin $args\n"
6455
6456	set fd [open "|$SPIN $args" r+]
6457
6458	catch "flush $fd"
6459
6460	$swin delete 0.0 end
6461	set step 0
6462	set lnr 1
6463
6464	$msc delete session
6465	$msc delete wherearewe
6466	$msc delete sno
6467	$msc delete vartrack
6468
6469	set msc_x 75
6470	set msc_y 20
6471	set msc_max_x $msc_x
6472	set Banner ""
6473
6474	if {$s_typ == 2} {
6475		catch { foreach el [array names Choice] { unset Choice($el) } }
6476	}
6477
6478	while {$stop == 0 && [eof $fd] == 0 && [gets $fd line] > -1} {
6479		if {$line == ""} {
6480			continue
6481		}
6482		if {[string first "type return to proceed" $line] > 0} {
6483			catch { puts $fd ""; flush $fd }
6484			update
6485			continue
6486		}
6487## interactive mode only:
6488		if {$s_typ == 2} {
6489			if {[string first "Select stmnt" $line] >= 0 \
6490			||  [string first "Select a statement" $line] >= 0} {
6491				set Banner $line
6492				continue
6493			}
6494			if {[string first "choice " $line] >= 0} {
6495				if {[string first " unexecutable" $line] < 0 \
6496				&&  [string first " outside range" $line] < 0} {
6497					scan $line "	choice %d:" which
6498					set NN [string first ":" $line]
6499					incr NN 2
6500					set what [string range $line $NN end]
6501					set Choice($which) $what
6502			##		$swin insert end "=$which=$what== $line\n"
6503				}
6504				continue
6505			}
6506			if {[string first "Make Selection" $line] >= 0} {
6507				set nr [pickoption $Banner]
6508				catch { puts $fd "$nr"; flush $fd }
6509				if {$nr == "q\n"} { set stop 1 }
6510				continue
6511		}	}
6512
6513		set i [string first "<merge" $line]
6514		if {$i > 0} {
6515			incr i -1
6516			set line [string range $line 0 $i]
6517			set line [string trimright $line]
6518		}
6519
6520		set ipc [string first "\[values: " $line]
6521		if {$ipc > 0} {		;# send or receive action
6522			incr ipc 9
6523			set epc [string last "\]" $line]
6524			if {$epc > $ipc} {
6525				incr epc -1
6526				set stmnt [string range $line $ipc $epc]
6527				# eg 5!first,7
6528				set snd [string first "!" $stmnt]
6529				if {$snd > 0} {
6530					incr snd -1
6531					set qno [string range $stmnt 0 $snd]
6532					set istype 1	;# send
6533				} else {
6534					set rcv [string first "?" $stmnt]
6535					incr rcv -1
6536					set qno [string range $stmnt 0 $rcv]
6537					set istype 2	;# recv
6538				}
6539				if {$qfilter == "" || [regexp $qfilter $qno] > 0} {
6540					if {[scan $line "%d:	proc %d (%s)" sno prno pnm] == 3} {
6541
6542						regexp {[A-Za-z0-9_\.]+:[0-9]+} $line matched
6543						if {$matched != ""} {
6544							set splitx [split $matched ":"]
6545							set fnm [lindex $splitx 0]
6546							set zzz [lindex $splitx 1]
6547						}
6548
6549						if {$pfilter == "" || [regexp $pfilter $prno] > 0} {
6550							set pnm [string trimright $pnm ")"]
6551							put_msc 1 $sno $prno $stmnt [expr $step + 1] $pnm $fnm $zzz
6552							catch { handle_ipc $qno $istype }
6553							incr msc_y $msc_h
6554				}	}	}
6555			}
6556			continue
6557		}
6558
6559		if {[scan $line "%d:	proc %d " sno prno] == 2} {	;# process line: transition info
6560			set nstep [expr $step + 1]
6561			foreach el [array names Varnm] {
6562				if [info exists VarStep([list $step $el])] {
6563					set xx $VarStep([list $step $el])
6564					set VarStep([list $nstep $el]) $xx
6565			}	}
6566			foreach el [array names Qnm] {
6567				if [info exists QStep([list $step $el])] {
6568					set xx $QStep([list $step $el])
6569					set QStep([list $nstep $el]) $xx
6570			}	}
6571
6572			if [info exists LineNo($step)] {
6573				set LineNo($nstep) $LineNo($step)
6574			} else {
6575				set LineNo($nstep) 0
6576			}
6577			incr step
6578			if {$step > $maxn} { set maxn $step }
6579
6580			if {$pfilter == "" || [regexp $pfilter $prno] > 0} {
6581				if {[string first "\[.(goto)\]" $line] > 0 \
6582				||  [string first "goto :" $line] > 0} {
6583					continue
6584				}
6585				$swin insert end "$line\n"
6586				line_bindings $lnr $prno $sno $line
6587				lines_touched	;# update
6588				incr lnr
6589			}
6590		} else {		;# variables, queues, and other info
6591			if {[string first " = " $line] > 0 } {
6592				set isvar [string first "=" $line]
6593				set isvar [expr $isvar + 1]
6594				set varvl [string range $line $isvar end]
6595				set isvar [expr $isvar - 2]
6596				set varnm [string range $line 0 $isvar]
6597				set varnm [string trim $varnm "	"]
6598
6599				if {$vfilter == "" || [regexp $vfilter $varnm] > 0} {
6600					set Varnm($varnm) 1
6601					set VarStep([list $step $varnm]) $varvl
6602					var_update $step
6603					if {$tfilter != "" && [regexp $tfilter $varnm] > 0} {
6604						var_track $varnm $varvl $tscale
6605					}
6606				}
6607			} else {	;# not a variable update
6608					;# check for queue contents
6609				set qstart [string first "	queue " $line]
6610				if {$qstart > 0} {
6611					incr qstart 7
6612					set ltail [string range $line $qstart end]
6613					set qend [string first " " $ltail]
6614					set qno [string range $ltail 0 $qend]
6615					if {$qfilter == "" || [regexp $qfilter $qno] > 0} {
6616						set Qnm($qno) 1
6617						set QStep([list $step $qno]) $ltail
6618						queue_update $step
6619					}
6620				} else {
6621					# could be never claim move
6622					set nvr [string first ":never:" $line]
6623					if {$nvr > 0} {
6624						incr nvr 8
6625						set envr $nvr
6626						while {[string is integer [string range $line $envr [expr $envr + 1]]]} {
6627							incr envr
6628						}
6629						set clmnt [string range $line $nvr $envr]
6630						set line "	(never) [string range $line $nvr end]"
6631					}
6632					$swin insert end "$line\n"; incr lnr
6633		}	}	}
6634	}
6635
6636	if {$stop == 1} {
6637		while {[eof $fd] == 0 && [gets $fd line] > -1} {
6638			if {[string first "type return to proceed" $line] > 0} {
6639				puts $fd "q"
6640				flush $fd
6641				break
6642		}	}
6643	}
6644	catch "close $fd"
6645
6646	catch {
6647		$x.run.ctl.reset configure -fg gold -command rewind
6648	}
6649
6650	bind_lines $swin $rwin
6651}
6652
6653proc add_log {s c} {
6654	global clog twin cnt
6655
6656	if {$c} {
6657		$clog insert end "$cnt $s\n"
6658		incr cnt
6659	} else {
6660		$clog insert end "$s\n"
6661	}
6662	bind_lines $clog $twin
6663	$clog yview -pickplace end
6664}
6665
6666proc runsyntax {a} {
6667	global twin swin pane
6668
6669	if {[$twin edit modified]} {
6670		set answer [tk_messageBox -icon question -type yesno \
6671		-message "There are unsaved changes. Save first?" ]
6672		switch -- $answer {
6673		yes { save_spec 0; open_spec 0 }
6674		no  { }
6675		}
6676	}
6677
6678	if {$a} {
6679		add_log "redundancies" 1
6680	} else {
6681		add_log "syntax check" 1
6682	}
6683	syntax_check $a $swin
6684}
6685
6686proc cleanup {} {
6687	global Fname RM
6688	catch { eval exec $RM never_claim.tmp }
6689	catch { eval exec $RM $Fname.nvr spinbat.bat dot.tmp dot.out dot.sel pan.tmp }
6690	catch { eval exec $RM pan.t pan.m pan.h pan.c pan.b pan.p pan.pre }
6691	catch { eval exec $RM run.tmp pan.exe pan }
6692}
6693
6694proc syntax_check {a into} {
6695	global clog Fname SPIN Unix
6696
6697	if {$Fname == ""} {
6698		add_log "no model" 0
6699		return
6700	}
6701
6702	set SPINBAT $SPIN	;# default
6703	if {$Unix == 0} {	;# on Windows systems only
6704		if [catch {set fd [open "spinbat.bat" w 0777]} errmsg] {
6705			;# same as default
6706		} else {
6707			set SPINBAT "./spinbat.bat"	;# avoids windows popping up
6708			puts $fd "@spin %1 %2\n"
6709			catch "close $fd"
6710	}	}
6711
6712	set cnt 0
6713	if {$a} { set args "-A" } else { set args "-a" }
6714	catch {eval exec $SPINBAT $args $Fname} err
6715	$into delete 0.0 end
6716	if {$err == ""} {
6717		add_log "spin: nothing to report" 0
6718	} else {
6719		add_log "$err" 0
6720	}
6721	update
6722	cleanup
6723}
6724
6725proc forAllMatches {w pattern} {
6726	global lno SFG
6727
6728	$w tag remove hilite 0.0 end
6729
6730	scan [$w index end] %d numLines
6731	for {set i 1} {$i < $numLines} { incr i} {
6732		$w mark set last $i.0
6733		if {[regexp -indices $pattern \
6734			[$w get last "last lineend"] indices]} {
6735				$w mark set first \
6736					"last + [lindex $indices 0] chars"
6737				$w mark set last "last + 1 chars \
6738					+ [lindex $indices 1] chars"
6739			$w tag add hilite $i.0 $i.end
6740			$w tag configure hilite -foreground $SFG
6741	}	}
6742
6743	# move to the next line that matches
6744	for {set i [expr $lno+1]} {$i < $numLines} { incr i} {
6745		$w mark set last $i.0
6746		if {[regexp -indices $pattern \
6747			[$w get last "last lineend"] indices]} {
6748				$w mark set first \
6749					"last + [lindex $indices 0] chars"
6750				$w mark set last "last + 1 chars \
6751					+ [lindex $indices 1] chars"
6752			$w yview -pickplace [expr $i-5]
6753			set lno $i
6754			return
6755	}	}
6756	for {set i 1} {$i <= $lno} { incr i} {
6757		$w mark set last $i.0
6758		if {[regexp -indices $pattern \
6759			[$w get last "last lineend"] indices]} {
6760				$w mark set first \
6761					"last + [lindex $indices 0] chars"
6762				$w mark set last "last + 1 chars \
6763					+ [lindex $indices 1] chars"
6764			$w yview -pickplace [expr $i-5]
6765			set lno $i
6766			return
6767	}	}
6768	add_log "no match found of \"$pattern\"" 0
6769}
6770
6771proc file_ok {f} {
6772
6773	if {[file exists $f]} {
6774		if {![file isfile $f] || ![file writable $f]} {
6775			add_log "error: file $f is not writable" 0
6776			return 0
6777	}	}
6778	return 1
6779}
6780
6781proc update_master {w} {	;# called for rwin and vr
6782	global twin	;# to make w match twin
6783
6784	$twin delete 0.0 end
6785
6786	scan [$w index end] %d numLines
6787	incr numLines -1
6788	for {set i 1} {$i < $numLines} {incr i} {
6789		set line [$w get $i.0 $i.end]
6790		$twin insert end "$line\n"
6791	}
6792	set line [$w get $i.0 $i.end]
6793	if {$line != ""} {
6794		$twin insert end "$line\n"
6795	}
6796}
6797
6798proc update_ref {w} {	;# called for rwin and vr
6799	global twin	;# to make w match twin
6800
6801	$w delete 0.0 end
6802
6803	scan [$twin index end] %d numLines
6804	incr numLines -1
6805	for {set i 1} {$i < $numLines} {incr i} {
6806		set line [$twin get $i.0 $i.end]
6807		$w insert end "$line\n"
6808	}
6809	set line [$w get $i.0 $i.end]
6810	if {$line != ""} {
6811		$twin insert end "$line\n"
6812	}
6813}
6814
6815proc writeoutfile {to} {
6816	global Fname twin
6817
6818	if ![file_ok $to] { return 0 }
6819
6820	if [catch {set fd [open $to w]} errmsg] {
6821		add_log $errmsg 0
6822		return 0
6823	}
6824	fconfigure $fd -translation lf	;# no cr at end of line, just lf
6825
6826	scan [$twin index end] %d numLines
6827	for {set i 1} {$i < $numLines} {incr i} {
6828		set line [$twin get $i.0 $i.end]
6829		if {[scan $line "%d	" lnr] == 1} {
6830			set sol [string first "\t" $line]
6831			incr sol
6832			puts $fd [string range $line $sol end]
6833		} else {
6834			if {[string length $line] > 0} {
6835				puts $fd $line
6836	}	}	}
6837	close $fd
6838
6839	set Fname $to
6840	wm title . $Fname
6841	add_log "<saved $Fname>" 1
6842
6843	return 1
6844}
6845
6846proc readinfile {from} {
6847	global Fname CBG CFG LTL_Panel
6848	global vr twin rwin ltl_main
6849
6850	if [catch {set fd [open $from r]} errmsg] {
6851		add_log "$errmsg" 0
6852		return 0
6853	}
6854
6855#	$rwin configure -state normal
6856#	$twin configure -state normal
6857#	$vr configure -state normal
6858
6859	$rwin delete 0.0 end
6860	$twin delete 0.0 end
6861	$vr delete 0.0 end
6862
6863	set ln 1
6864	while {[gets $fd line] > -1} {
6865		$rwin insert end "$ln	$line\n"
6866		$twin insert end "$ln	$line\n"
6867		$vr insert end "$ln	$line\n"
6868		incr ln
6869	}
6870
6871#	$rwin configure -state disabled
6872#	$twin configure -state disabled
6873#	$vr configure -state disabled
6874	$twin edit modified false
6875
6876	catch { close $fd }
6877	add_log "$from:1" 1
6878
6879	set prf "[pwd]/"
6880	if {[string first $prf $from] == 0} {
6881		set from [string range $from [string length $prf] end]
6882	}
6883	set Fname $from
6884	wm title . "$Fname"
6885
6886	if {$LTL_Panel} {
6887		$ltl_main.left.frm.tmp delete 0 end
6888		if [catch {set fo [open "$Fname.ltl" r]} errmsg] {
6889		#	ltl_log "no ltl-file $Fname.ltl"
6890		} else {
6891			catch { close $fo }
6892			$ltl_main.left.frm.tmp insert insert "$Fname.ltl"
6893			reopen_ltl $ltl_main
6894	}	}
6895
6896	return 1
6897}
6898
6899proc open_spec {h} {
6900	global Fname x
6901
6902	if {$h == 1} {
6903		set ftypes {
6904			{{Promela File Format} {.pml} }
6905			{{All Files}	*}
6906		}
6907		switch -- [set file [tk_getOpenFile -filetypes $ftypes]] "" return
6908	} else {
6909		if {$Fname == ""} { return }
6910		set file $Fname
6911	}
6912
6913	if [readinfile $file] {
6914		set_path $Fname
6915	}
6916
6917	if {$Fname != ""} {
6918		$x.sms.int.fld4 delete 0 end
6919		$x.sms.int.fld4 insert end $Fname.trail
6920	}
6921}
6922
6923proc set_path {f} {
6924	global Fname
6925
6926	set fullpath [split $f /]
6927	set nlen [llength $fullpath]
6928	set Fname [lindex $fullpath [expr $nlen - 1]]
6929	wm title . "$Fname"
6930	set fullpath [lrange $fullpath 0 [expr $nlen - 2]] 	;# strip filename
6931	set wd [join $fullpath /] 				;# put path back together
6932 	catch {cd $wd}
6933}
6934
6935proc symbol_table {} {
6936	global clog SPIN Fname
6937
6938	if {$Fname == ""} {
6939		add_log "no model" 0
6940		return
6941	}
6942
6943	set ST	"$SPIN -d $Fname"
6944
6945	catch {set fd [open "|$ST" r]} errmsg
6946	if {$fd == -1} {
6947		$clog insert end "$errmsg\n"
6948		$clog yview end
6949		update
6950		return
6951	}
6952	$clog insert end "Symbol Table Information for $Fname:\n"
6953	while {[gets $fd line] > -1} {
6954		$clog insert end "$line\n"
6955		$clog yview end
6956		update
6957	}
6958	catch { close $fd }
6959}
6960
6961proc helper {} {
6962	global HV0 NBG NFG LTL_Panel
6963
6964	catch {destroy .hlp}
6965	toplevel .hlp -bg black
6966	wm title .hlp "Help with iSpin"
6967	wm iconname .hlp "Help"
6968	wm geometry .hlp 800x450+60+150
6969
6970	set hlp [NoteBook .hlp.x -bg black -fg $NFG -font $HV0 \
6971		-activebackground $NFG -activeforeground $NBG -side top]
6972
6973	pack .hlp.x -fill both -expand yes
6974
6975	g_hlp [$hlp insert end Gh -text " General " ]
6976	n_hlp [$hlp insert end Nh -text " What is New in 6.0 " ]
6977	m_hlp [$hlp insert end Mh -text " Edit/View? "   ]
6978	s_hlp [$hlp insert end Sh -text " Simulation/Replay? "   ]
6979
6980	if {$LTL_Panel} {
6981		l_hlp [$hlp insert end Lh -text " LTL Properties? "   ]
6982	}
6983	v_hlp [$hlp insert end Vh -text " Verification? "   ]
6984	sw_hlp [$hlp insert end Swh -text " Swarm? "   ]
6985	session_hlp [$hlp insert end Sessionh -text " Save/Restore Session? "   ]
6986	q_hlp [$hlp insert end Qh -text " Quit? "   ]
6987
6988	$hlp raise Gh
6989}
6990
6991proc boilerplate {t} {
6992	global version xversion CBG CFG HV1 ScrollBarSize
6993
6994        set x   [ScrolledWindow $t.sw -size $ScrollBarSize]
6995        set y   [text $x.lb -height 15 -width 100 -highlightthickness 3 -bg $CBG -fg $CFG -font $HV1]
6996	$x setwidget $y
6997	pack $x -fill both -expand yes
6998	return $y
6999}
7000
7001proc n_hlp {t} {
7002	set y [boilerplate $t]
7003
7004	$y insert end "Spin Version 6.0 has a number of new features.
7005
7006- Improved scope rules:
7007	so far, there were only two levels of scope for variable
7008	declarations: global or proctype local.
7009	6.0 supports the more traditional block scope as well:
7010	a variable declared inside an inline definition or inside
7011	a block has scope that is limited to that inline or block.
7012	You can revert to the old scope rules by using spin -O
7013- Multiple never claims:
7014	In 6.0 you can name never claims, by adding a name in
7015	between the keyword 'never' and the opening curly brace of
7016	the never claim body.
7017	This allows you to specify multiple never claims in a single
7018	Spin model. The model checker will still only use one never
7019	claim to perform the verification, but you can choose on the
7020	command line of pan which claim you want to use: pan -N name
7021- Synchronous product of claims:
7022	If multiple never claims are defined, you can use spin to
7023	generate a single claim which encodes the synchronous product
7024	of all never claims defined, using the new option -e:
7025	 spin -e spec.pml
7026- Inline ltl properties:
7027	Instead of specifying an explicit never claim, you can now
7028	specify LTL properties directly inline. Any number of named
7029	properties can be provided, and you can again choose which
7030	one should be checked, using the -N command line argument to pan.
7031	Example LTL property: ltl p1 \{ []<>p \}
7032	Inline LTL properties state positive properties to prove, i.e.,
7033	they are not negated. (When spin generates the corresponding
7034	never claim, it will perform the negation automatically, so that
7035	it can find counter-examples to the positive property.)
7036- Dot support:
7037	A new option for the executable pan supports the generation of
7038	the state tables in the format accepted by the dot tool from
7039	graphviz: pan -D (the ascii format is still available as pan -d).
7040- Standardized output:
7041	All filename / linenumber references are now in a single standard
7042	format, given as filename:linenumber, which allows postprocessing
7043	tools, like iSpin, to easily hotlink such references to the source.
7044"
7045}
7046
7047proc version_check {y} {
7048	global CURL
7049
7050	set TMP   _version_check_.tmp
7051	set URL   http://spinroot.com/spin/Src/index.html
7052
7053	if {[auto_execok $CURL] == ""} {
7054		return
7055	}
7056	catch { eval exec $RM $TMP }
7057	catch { eval exec $CURL -s -S $URL -o $TMP } err
7058	if {$err != ""} {
7059		catch { eval exec $RM $TMP }
7060		return
7061	}
7062	set fd -1
7063	catch { set fd [open $TMP r] }
7064	if {$fd != -1} {
7065	   while {[gets $fd line] > -1} {
7066		set want [string first "Current Version" $line]
7067		if {$want >= 0} {
7068			set ln [expr $want + [string length "Current Version "]]
7069			set el [string first ":" $line]
7070			$y insert end "The latest Spin Version is: "
7071			$y insert end "[string range $line $ln [expr $el - 1]] "
7072			$y insert end "(visit http://spinroot.com/spin/Bin)\n"
7073			break
7074	   }	}
7075	   catch { close $fd }
7076	}
7077	catch { eval exec $RM $TMP }
7078}
7079
7080proc g_hlp {t} {
7081	global version xversion
7082
7083	set y [boilerplate $t]
7084
7085	$y insert end "  $version\n  $xversion\n\n"
7086
7087	version_check $y
7088
7089	$y insert end "
7090  Spin is an on-the-fly LTL model checking system for proving properties
7091  of asynchronous software systems, and iSpin is a Graphical User Interface
7092  for Spin written in Tcl/Tk.
7093
7094  Click on one of the above tabs for a more detailed explanation of each
7095  options supported through this interface.
7096
7097  For the latest version of Spin, see:
7098	http://spinroot.com/spin/Bin (precompiled binaries)
7099  or
7100	http://spinroot.com/spin/Src (sources)
7101
7102  For help with Promela, the specification language used by Spin, see:
7103	http://spinroot.com/spin/Man/index.html    (overview)
7104	http://spinroot.com/spin/Man/promela.html  (manual pages)
7105
7106  For help not covered here and for bug-reports:  gholzmann @ acm.org
7107
7108  iSpin works only with Spin Version 6.0.0 or later.
7109
7110  Spin is (c) 1989-2003 Bell Laboratories, Lucent Technologies, Murray Hill, NJ, USA,
7111  Extensions 2003-2010 (c) JPL/Caltech. All rights reserved.
7112
7113  Spin and iSpin are for educational and research purposes only. No guarantee
7114  whatsoever is expressed or implied by the distribution of this code.
7115
7116  Last updated: 4 December 2010.
7117"
7118}
7119
7120proc m_hlp {t} {
7121
7122	set y [boilerplate $t]
7123
7124	$y insert end "
7125  This panel allows you to Open or Save a Promela verification models
7126  The default file extension for Promela models is .pml.
7127
7128  Syntax Check, Redundancy Check, and Symbol Table can be used to produce
7129  the corresponding output in the black log window at the bottom of the panel.
7130  Each command issued by iSpin is actually performed by standard Spin
7131  running in the background, so without Spin (or with the wrong version of
7132  Spin pre 6.0) not much of interest can happen.
7133
7134  Find allows you to locate a search string in the Promela model text.
7135
7136  The Automata View button (in the right side mid panel)
7137  populates the blue canvas with the names of proctypes and never claims.
7138  It does so by first generating and compiling the model checking code, so
7139  if there are syntax errors that prevent compilation, you will see those first.
7140
7141  Click on a name to generate the control-flow graph of the corresponding
7142  state machine. Currently, the text in the graphs does not scale when you zoom
7143  in or out, so this is still of some limited use.
7144  You can scroll the display by holding button 2 (middle button) down
7145  and moving the mouse.
7146"
7147}
7148
7149proc s_hlp {t} {
7150
7151	set y [boilerplate $t]
7152
7153	$y insert end "
7154  The Simulation panel has all options that are relevant for random or guided
7155  simulations of the model. A guided similation uses an error-trail produced
7156  in a Verification or Swarm run to guide the execution.
7157
7158  Run		button starts a simulation run
7159  Stop		stops it
7160  Rewind	rewinds a completed run to the start
7161
7162  Step Forward	moves one step forward through an earlier run
7163  Step Back	moves one step backwards through an earlier run
7164
7165  The background command executed by Spin to generate the output is shown in the box at the top right.
7166
7167  Clicking on a line of text in the Simulation output panel moves to that line
7168  and updates variable values and queue contents values to that point in the execution.
7169  You can also click on the boxes in an MSC display to achieve the same effect.
7170
7171  The entry box for process ids allows you to define a regular expression of pids
7172  that will be used to restrict the output to only processes with matching pids,
7173  for instance you can use 1|3 to display output for only processes 1 and 3
7174  or use \[^1-3\] to suppress output for processes 1, 2, and 3
7175
7176  The entry box for queue ids similarly allows the definition of a regular expression
7177  filter for operations on channels.
7178
7179  The entry box for var names allows you to restrict the output in the Data Values
7180  panel to only variable names matching the regular expression given
7181
7182  The entry box for tracked variable is an experimental option to display a bar in
7183  the MSC panel indicating the size of the variable specified -- the size of the
7184  bar can be scaled with the value given in the track scaling box (e.g., 10 or 0.01).
7185"
7186}
7187
7188proc l_hlp {t} {
7189
7190	set y [boilerplate $t]
7191
7192	$y insert end "
7193  Define an LTL formula in the top box, using the black buttons as
7194  short-hands if needed. Define any necessary symbols as macros in
7195  the Symbols panel, add notes to explain what it is you are trying
7196  to express in the Notes panel and then click the Never Claim bar
7197  (or type return in the Formula entry box) to generate the never claim.
7198
7199  You can save a filled in Properties panel as a template with the Save as button,
7200  and you can (re)load the contents of this panel from an earlier template by
7201  giving a file name in the Template file entry box (top right) and clicking ReLoad.
7202
7203  You can load an LTL template with a previously saved LTL
7204  formula from a file via the Browse button on the upper
7205  right of the LTL Property Manager panel.
7206
7207  See also the Help button on the far right on this panel -- with more detailed guidance.
7208"
7209}
7210
7211proc v_hlp {t} {
7212
7213	set y [boilerplate $t]
7214
7215	$y insert end "
7216  Many options are available here; the purpose of most will be clear from the labels.
7217
7218  A good practice is to go through the options from left to right:
7219	first choosing the type of verification to be done
7220	then what types of error trails you want to see
7221	next the specific type of search to be done (leave it at the default
7222	setting if you can't decide)
7223	next choose a storage mode (again, keep the default if you don't
7224	have a good reason to change it). the options other than exhaustive
7225	are there just to help you reduce memory.
7226  The panel at the far right allows you to provide more detailed parameters.
7227	each of these parameters comes with a short explanation -- press the
7228	'explain' button next to the parameter to check this.
7229
7230  Run generates and compiles the model checker and will execute it (if no errors
7231  prevent the compilation). You can interrupt a long running verification run with the
7232  Stop button.
7233
7234  Use the Help button (on the far right, in the middle) gives more detailed information
7235  on methods to reduce verification complexity.
7236"
7237}
7238
7239proc sw_hlp {t} {
7240
7241	set y [boilerplate $t]
7242
7243	$y insert end "
7244  This panel allows you to configure a Swarm verification run, which can be quite effective
7245  for large models. You specify the maximum runtime and the number of CPU cores
7246  to use (do not exceed the number of cores on your system). To use this option,
7247  you must have the swarm preprocessor installed on your system.
7248
7249  You can download swarm from: http://spinroot.com/swarm
7250"
7251}
7252
7253proc session_hlp {t} {
7254
7255	set y [boilerplate $t]
7256
7257	$y insert end "
7258  Save Session:
7259  	Saves the state and contents of *all* panels and selections made,
7260  	as well as all textual outputs displayed.
7261
7262  	The data is recorded in a session snapshot file with file extension .isf
7263
7264  Restore Session:
7265  	Restores the iSpin displays and selections to the a previously saved state."
7266}
7267
7268proc q_hlp {t} {
7269
7270	set y [boilerplate $t]
7271
7272	$y insert end "
7273  Performs an orderly exit from iSpin, cleaning up temporary files, etc.
7274  If you forgot to save a modified model, you'll get a warning.
7275
7276  You can of course also just kill the window itself -- but then none of these
7277  niceties will happen.
7278"
7279}
7280
7281proc find_field {fld ln} {
7282
7283	set a [string first "$fld" $ln]
7284	incr a [string length "$fld"]
7285
7286	set b [string first "\"" [string range $ln $a end]]
7287	if {$b <= 0} {
7288		set b [string first "," [string range $ln $a end]]
7289	}
7290	if {$b <= 0} {
7291		set b [string first "\]" [string range $ln $a end]]
7292	}
7293	set b [expr $a + $b - 1]
7294
7295	set mf [string range $ln $a $b]
7296	if {$mf == ""} { set mf 1 }
7297
7298	return [expr 50 * $mf]
7299}
7300
7301proc display_graph {pn} {
7302	global fg RM DOT
7303
7304	add_log "select $pn" 1
7305	set found 0
7306	set fd [open dot.tmp r]
7307	set fo [open dot.out w]
7308	while {[gets $fd line] > -1} {
7309		if {[string first "digraph" $line] >= 0} {
7310			if {[string first "$pn" $line] >= 0} {
7311				set found 1
7312			} else {
7313				set found 0
7314		}	}
7315		if {$found} {
7316			puts $fo "$line"
7317	}	}
7318	catch { close $fd }
7319	catch { close $fo }
7320	# do not overwrite dot.tmp
7321	catch { eval exec \"$DOT\" -Ttk < dot.out > dot.sel } err
7322	if {$err != ""} {
7323		add_log "$err" 0
7324		tk_messageBox -icon info -message "pan: $err"
7325		return
7326	}
7327
7328	catch { $fg delete graph }
7329	set c $fg
7330	set fd [open dot.sel r]
7331	while {[gets $fd line] > -1} {
7332		if {[string first "#" $line] < 0} {
7333			if {[string first "create polygon" $line] > 0} {
7334				set line [string map {black red} $line]
7335				set line [string map {white black} $line]
7336			}
7337			if {[string first "create oval" $line] > 0} {
7338				set line [string map {black ivory} $line]	;# outline black -> ivory
7339				set line [string map {white black} $line]	;# fill white -> black
7340			}
7341			if {[string first "create line" $line] > 0} {
7342				set line [string map {black ivory} $line]
7343			}
7344			if {[string first "create text" $line] > 0} {
7345				set line [string map {black gold} $line]
7346			}
7347			eval $line -tags graph
7348	}	}
7349	catch { close $fd }
7350	catch { eval $RM dot.sel dot.out }	;# cannot delete dot.tmp yet
7351}
7352
7353proc mk_graphs {} {
7354	global fg Fname SPIN CC DOT HV1 RM
7355
7356	if {$Fname == ""} { return }
7357
7358	if {[auto_execok $DOT] == ""} {
7359		tk_messageBox -icon info -message "ispin: cannot find $DOT"
7360		return
7361	}
7362
7363	add_log "$SPIN -o3 -a $Fname" 1
7364	catch { eval exec $SPIN -o3 -a $Fname } err
7365	if {$err != ""} {
7366		if {[string first "Error:" $err] > 0} {
7367			tk_messageBox -icon info -message "spin: $err"
7368			return
7369		}
7370		add_log "$err" 0
7371	}
7372	add_log "$CC -o pan pan.c" 1
7373	catch { eval exec $CC -w -o pan pan.c } err
7374	if {$err != ""} {
7375		add_log "$err" 0
7376		tk_messageBox -icon info -message "cc: $err"
7377		return
7378	}
7379
7380	# use output from ./pan -D to build menu
7381	add_log "./pan -D > dot.tmp" 1
7382	catch { eval exec ./pan -D > dot.tmp } err
7383	if {$err != ""} {
7384		add_log "$err" 0
7385		tk_messageBox -icon info -message "pan: $err"
7386		return
7387	}
7388	set dx 50
7389	set dy 20
7390
7391	catch { $fg delete hotlinks }
7392	catch { $fg delete graph }
7393	set hl [$fg create text $dx $dy -text "Select:" \
7394			-font $HV1 -fill white -tags hotlinks]
7395	incr dy 15
7396	set fd [open dot.tmp r]
7397	while {[gets $fd line] > -1} {
7398		if {[string first "digraph" $line] >= 0} {
7399			set x [string first "\{" $line]
7400			set pn [string trim [string range $line 8 [expr $x - 1]]]
7401
7402			set hl [$fg create text $dx $dy \
7403				-text $pn -font $HV1 -fill lightblue -tags hotlinks]
7404			incr dy 15
7405
7406			$fg bind $hl <Any-Enter> "
7407				$fg itemconfigure $hl -fill gold
7408			"
7409			$fg bind $hl <Any-Leave> "
7410				$fg itemconfigure $hl -fill lightblue
7411			"
7412			$fg bind $hl <ButtonPress-1> "
7413				display_graph $pn
7414			"
7415	}	}
7416	catch { close $fd }
7417}
7418
7419#### Startup
7420	create_panels
7421
7422	add_log "$version" 0
7423	add_log "$xversion" 0
7424	add_log "TclTk Version [info tclversion]/$tk_version" 0
7425
7426	if {$argc == 1} {
7427		set Fname "$argv"
7428		open_spec 0
7429	}
7430
7431	update
7432
7433