source: tol/tolbase/lib/mkWidgets1.3/metawidget.tcl @ a680983

1941-docker-image-to-testdevel
Last change on this file since a680983 was 32535cc, checked in by Jorge Pérez <josp.jorge@…>, 18 years ago

adding more types to config, added mkWidget1.3

git-svn-id: ​https://www.tol-project.org/svn/tolp/trunk@16 be4846ae-f051-483a-831f-b64e7d08527f

  • Property mode set to 100644
File size: 25.5 KB
Line 
1package provide Metawidget 1.3
2
3# all new procedures are defined in the metawidget namespace. each created
4# metawidget will use its own namespace, which has the name of the widget's
5# class. in such a class namespace, all procedures defined for the class
6# are held, as well as arrays containing information about commands and
7# options. also, class common variables are stored in the class namespace.
8# each instance of a metawidget defines another namespace with its name,
9# where all private variables are held.
10namespace eval ::metawidget {
11  # name: metawidget
12  # args: -
13  # the only command exported by this package for use outside of actual
14  # metawidget code. all others can or should only be used within
15  # procedure definitions of metawidgets. this command allows to create,
16  # delete, and build a metawidget.
17  proc metawidget { sCmd {sClass {}} args } {
18    set sCommand [mkw.complete $sCmd {create delete command option proc names info export}]
19    set iArgc [llength $args]
20
21    switch $sCommand {
22      create {
23        # creates a metawidget by calling _createClass. constructor and
24        # destructor scripts must be provided, plus a list of options that
25        # specify a) the widget type for the enclosing widget, b) the
26        # (relative) name of the widget where all calls to configure and
27        # cget are applied to, and c) any number of option-value pairs
28        # to configure the enclosing widget.
29        if { $iArgc < 2 } {
30          error "Wrong # args: Must be metawidget create class initbody destroybody ?options?"
31        } elseif { ! [string match {[A-Z]*} $sClass] } {
32          error "Bad metawidget class name '$sClass'. Class name must start with uppercase character"
33        }
34
35        set sConstr [lindex $args 0]
36        set sDestr  [lindex $args 1]
37        set lArgs   [lrange $args 2 end]
38
39        _createClass $sClass $sConstr $sDestr $lArgs
40
41        # store new metawidget in list of all metawidgets
42        variable lMetawidgets
43        set lMetawidgets [mkw.lextend $lMetawidgets $sClass]
44      }
45
46      delete {
47        # deletes a metawidget by deleting its namespace
48        if { $iArgc > 0 } {
49          error "Wrong # args: Must be metawidget delete class"
50        }
51
52        _checkClass $sClass
53        namespace delete ::$sClass
54
55        # remove metawidget from list of all metawidgets
56        variable lMetawidgets
57        set lMetawidgets [mkw.lshrink $lMetawidgets $sClass]
58      }
59
60      proc {
61        # defines a metawidget procedure. this is just like any other
62        # procedure, i.e. it has a name, args and body, except that it
63        # is created in the metawidget's namespace, plus its variable
64        # context always contains a variable 'this' that holds the
65        # name of the current widget instance.
66        if { $iArgc != 3 } {
67          error "Wrong # args: Must be metawidget proc class name args body"
68        }
69
70        _checkClass $sClass
71        mkw.lassign $args sProc lArgs sBody
72
73        if { [lsearch [list $sClass ~$sClass __dispatch __configure __cget] $sProc] != -1 } {
74          error "Bad proc name '$sProc': This name is predefined or reserved."
75        }
76
77        proc ::${sClass}::$sProc $lArgs "
78          upvar this this
79          $sBody
80        "
81      }
82
83      command {
84        # defines a metawidget command. a metawidget command does not contain
85        # own code but is simply mapped to a metawidget procedure. therefore,
86        # two arguments are expected: command name and procedure name.
87        # this information is stored in an array within the metawidget's
88        # namespace.
89        if { $iArgc != 2 } {
90          error "Wrong # args: Must be metawidget command class name proc"
91        }
92
93        _checkClass $sClass
94        mkw.lassign $args sCommand sProc
95
96        set ::${sClass}::__aCmd($sCommand) $sProc
97      }
98
99      option {
100        # defines a metawidget option. a metawidget option is an option that
101        # cannot be mapped to the default widget, but is handled explicitely
102        # by the metawidget itself. the first argument to this call must be
103        # the option name. there are three ways how to implement an option:
104        # a) no additional arguments: if the option is set, then a private
105        # variable with the same name as the option is set. if the option
106        # is retrieved, the value is taken from that private variable.
107        # b) one argument: this must specify a procedure that actually
108        # sets the option, i.e. contains necessary code to process it.
109        # if the option is retrieved, the value is taken from a private
110        # variable with the same name as the option. therefore the
111        # specified procedure *must* eventually set this private variable!
112        # c) two arguments: like above, but the second argument is used
113        # to retrieve the option value. no private variable needs to be set.
114        if { $iArgc < 1 || $iArgc > 3 } {
115          error "Wrong # args: Must be metawidget option class name ?setProc? ?getProc?"
116        }
117
118        _checkClass $sClass
119        mkw.lassign $args sOption sSetProc sGetProc
120
121        switch $iArgc {
122          1 { set ::${sClass}::__aOpt($sOption) {} }
123          2 { set ::${sClass}::__aOpt($sOption) [list $sSetProc] }
124          3 { set ::${sClass}::__aOpt($sOption) [list $sSetProc $sGetProc] }
125        }
126      }
127
128      names {
129        # returns the names of all defined metawidgets
130        if { $iArgc } {
131          error "Wrong # args: Must be metawidget names"
132        }
133
134        variable lMetawidgets
135        return $lMetawidgets
136      }
137
138      info {
139        # returns various information about metawidgets
140        if { $iArgc != 1 } {
141          error "Wrong # args: Must be metawidget info name option"
142        }
143
144        _checkClass $sClass
145        _getInfo $sClass [lindex $args 0]
146      }
147
148      export {
149        # returns the metawidget's current namespace code. this code
150        # would create the metawidget without mkWidgets installed.
151        if { $iArgc != 0 } {
152          error "Wrong # args: Must be metawidget export name"
153        }
154
155        _checkClass $sClass
156
157        set sCmd "namespace eval ::$sClass {\n"
158
159        append sCmd "  array set __aOpt \[list [array get ::${sClass}::__aOpt]\]\n"
160        append sCmd "  array set __aCmd \[list [array get ::${sClass}::__aCmd]\]\n\n"
161
162        foreach sProc [lsort [info procs ::${sClass}::*]] {
163          append sCmd "  proc [namespace tail $sProc] { "
164          foreach sArg [info args $sProc] {
165            if { [info default $sProc $sArg sDefault] } {
166              append sCmd "{$sArg {$sDefault}} "
167            } else {
168              append sCmd "$sArg "
169            }
170          }
171          append sCmd "} {[info body $sProc]}\n\n"
172        }
173
174        append sCmd "  namespace export $sClass\n}\n\n"
175
176        append sCmd "namespace eval :: {
177          namespace import ::${sClass}::$sClass
178          rename $sClass [string tolower $sClass]
179        }"
180      }
181    }
182  }
183
184  # name: _checkClass
185  # args: sClass: metawidget class name
186  # simply checks if a namespace with the name $sClass exists. not really
187  # a bulletproof check.
188  proc _checkClass { sClass } {
189    if { [info command ::${sClass}::$sClass] == "" } {
190      error "Metawidget $sClass does not exist."
191    }
192  }
193
194  # name: _createClass
195  # args: sClass: metawidget class to create
196  #       sConstr: constructor
197  #       sDestr: destructor
198  #       lArgs: option-value pairs
199  # creates the framework for a new metawidget: it defines a new namespace
200  # and imports the my/our functions that handle private/class common
201  # variables as well as the mkw.* tool functions. then creates and exports
202  # the new widget command within the new namespace, which will embedd
203  # the constructor script. also defines a proc holding the destructor
204  # (called from a <destroy> event, and the standard widget commands
205  # configure and cget.
206  proc _createClass { sClass sConstr sDestr lArgs } {
207    # extract special options, the rest is for the default widget
208    set lArgs [mkw.options $lArgs * {-default *} {-type {frame toplevel} frame} {-command *}]
209
210    # type is the widget type for the enclosing widget (a frame by default)
211    set sType [string tolower ${-type}]
212
213    # if no command name specified, it will be sClass in lower case
214    if { [info exists -command] } {
215      set sCommand ${-command}
216    } else {
217      set sCommand [string tolower $sClass]
218    }
219
220    # if no default widget specifies, we take the enclosing widget
221    if { [info exists -default] } {
222      set wDefault \$this.${-default}
223    } else {
224      set wDefault \${this}::\$this
225    }
226
227    # create a namespace for the new metawidget class
228    namespace eval ::$sClass "
229      # this creates an instance of the new metawidget class. this is the name
230      # of the widget, args are option-value pairs.
231      proc $sClass { this args } {
232        # create enclosing widget (normally a frame), and configure it with the
233        # options specified during the metawidget's definition.
234        eval {$sType} {\$this} -class {$sClass} $lArgs
235
236        # exchange the class name in the widget's bindtags
237        bindtags \$this \[lreplace \[bindtags \$this\] 1 1 $sClass\]
238
239        # move the widget from the global into its own namespace...
240        rename ::\$this ::\${this}::\$this
241
242        # ...and create a procedure instead, that takes the same args as
243        # a widget would. it will pass the args to the dispatch procedure.
244        namespace eval :: \"
245          proc \$this { {sCmd {}} args } {
246            ::${sClass}::__dispatch \$this \\\$sCmd \\\$args
247          }
248        \"
249
250        # then evaluate the constructor script
251        $sConstr
252
253        # configure the default widget, if options were passed in args
254        eval __configure \$args
255
256        return \$this
257      }
258
259      # this is called when a widget is destroyed. evaluates the destructor
260      # script and deletes the widget's namespace.
261      proc ~$sClass { this } {
262        $sDestr
263        namespace delete ::\$this
264      }
265
266      # whenever a metawidget command is called (e.g. '.mycombobox config
267      # -state normal'), the widget uses this procedure to call the
268      # corresponding metawidget procedure. it also resolves abbreviated
269      # command names. if the command called is not defined, it applies
270      # it to the default widget.
271      proc __dispatch { this sCmd lArgs } {
272        if { \$sCmd == {} } {
273          error \"Wrong # args: Should be '\$this command args ?args ...?'\"
274        }
275
276        # here are all commands and their associated procs
277        variable __aCmd
278
279        # if the command is not in the array, it might be abbreviated
280        if { \[info exists __aCmd(\$sCmd)\] } {
281          eval {\$__aCmd(\$sCmd)} \$lArgs
282        } else {
283          set sCommand \[array names __aCmd \${sCmd}*\]
284          set iMatches \[llength \$sCommand\]
285
286          if { \$iMatches == 1 } {
287            eval {\$__aCmd(\$sCommand)} \$lArgs    ;# successfully resolved
288          } elseif { \$iMatches == 0 } {
289            eval {$wDefault} {\$sCmd} \$lArgs      ;# not found, try default
290          } else {
291            error \"Ambiguous command '\$sCmd': Must be \[join \[array names __aCmd\] {, }\]\"
292          }
293        }
294      }
295
296      # each widget understands the configure and cget commands. therefore a
297      # metawidget comes with them, too. this proc reads all the option-value
298      # pairs in args and does a lookup in the option array. if it does not
299      # find it, it applies the option to the default widget. otherwise it
300      # either sets a private variable or calls the associated proc.
301      proc __configure { args } {
302        upvar this this
303        variable __aOpt
304
305        set iArgs \[llength \$args\]
306
307        if { \$iArgs == 0 } {                        ;# return all options
308          return \"Function not yet implemented\"
309        } elseif { \$iArgs == 1 } {                  ;# return data for option
310          return \"Function not yet implemented\"
311        } elseif { \[expr \$iArgs % 2\] } {          ;# odd number of args
312          error \"Failed to configure \$this: Invalid number of arguments\"
313        } else {                                     ;# process options
314          foreach { sOpt sValue } \$args {
315            if { \[info exists __aOpt(\$sOpt)\] } {  ;# found in array
316              set sOption \$sOpt
317            } else {                                 ;# not found, resolve it
318              set sOption \[array names __aOpt \${sOpt}*\]
319              set iMatches \[llength \$sOption\]
320
321              if { \$iMatches == 0 } {               ;# not found, try default
322                $wDefault configure \$sOpt \$sValue
323                continue
324              } elseif { \$iMatches > 1 } {
325                error \"Ambiguous option '\$sOpt': Must be \[join \[array names __aOpt\] {, }\]\"
326              }
327            }
328
329            if { \[llength \$__aOpt(\$sOption)\] == 0 } { ;# just set variable
330              my \$sOpt \$sValue
331            } else {                                      ;# call procedure
332              eval \[lindex \$__aOpt(\$sOption) 0\] {\$sValue}
333            }
334          }
335        }
336      }
337
338      # similar to __configure. looks up the option array. if it does not find
339      # the option there, then it tries to get the value from the default
340      # widget. otherwise either gets it from a private variable or from
341      # the associated procedure.
342      proc __cget { sOpt } {
343        upvar this this
344        variable __aOpt
345
346        if { \[catch {llength \$__aOpt(\$sOpt)} iLen\] } {
347          $wDefault cget \$sOpt
348        } elseif { \$iLen != 2 } {
349          my \$sOpt
350        } else {
351          eval \[lindex \$__aOpt(\$sOpt) 1\]
352        }
353      }
354
355      # this will call the destructor on deletion of the widget
356      bind $sClass <Destroy> {::${sClass}::~$sClass %W}
357
358      # preset the commands array with the standard commands configure and cget
359      set __aCmd(configure) __configure
360      set __aCmd(cget)      __cget
361
362      # finally export the new class command and import the other stuff
363      namespace export $sClass
364      namespace import ::metawidget::un* ::metawidget::my* ::metawidget::our* ::metawidget::mkw.*
365    "
366
367    # in the global namespace, import the new class command and immediately
368    # rename it to the widget command (normally lower case).
369    namespace eval :: "
370      namespace import ::${sClass}::$sClass
371      rename $sClass $sCommand
372    "
373  }
374
375  # name: _getInfo
376  # args: sClass: metawidget class
377  #       sOption: procs, commands, or options
378  # returns information about a metawidget. for procs, returns a list of
379  # defined metawidget procedures, where each element consists of a sublist
380  # with the three elements procecure name, args, body. for commands, returns
381  # a list of defined metawidget commands, where each element consists of a
382  # sublist containing the command name and its associated procedure.
383  # for options, returns a list of defined metawidget options, where each
384  # element consists of a list containing the elements option name, set-
385  # procedure (if defined) and get-procedure (if defined).
386  proc _getInfo { sClass sOption } {
387    switch [mkw.complete $sOption {procs commands options}] {
388      procs {
389        set lProcs {}
390        foreach sProc [info procs ::${sClass}::*] {
391          lappend lProcs [list [namespace tail $sProc] [info args $sProc] [info body $sProc]]
392        }
393
394        return [lsort -index 0 $lProcs]
395      }
396
397      commands {
398        set lCmds {}
399        foreach {sCmd sProc} [array get ::${sClass}::__aCmd] {
400          lappend lCmds [list $sCmd $sProc]
401        }
402
403        return [lsort -index 0 $lCmds]
404      }
405
406      options {
407        set lOpts {}
408        foreach {sOpt lProcs} [array get ::${sClass}::__aOpt] {
409          lappend lOpts [list $sOpt $lProcs]
410        }
411
412        return [lsort -index 0 $lOpts]
413      }
414    }
415  }
416
417  # name: my
418  # args: args: varname ?value?
419  # sets or retrieves a private variable. very similar to the set command.
420  # sets a variable in the widget's namespace.
421  proc my { args } {
422    upvar this this
423    namespace eval ::$this set $args
424  }
425
426  # name: unmy
427  # args: args: list of private variables
428  # unsets private variables, just like the unset command.
429  proc unmy { args } {
430    upvar this this
431    namespace eval ::$this "catch {unset $args}"
432  }
433
434  # name: myarray
435  # args: args: anything allowed for the array command
436  # performs array operations on private arrays. maps to the array command.
437  proc myarray { args } {
438    upvar this this
439    namespace eval ::$this array $args
440  }
441
442  # name: myinfo
443  # args: sOption: class, exists, vars
444  #       args: depends on sOption
445  # provides information regarding the widget and its state. 'class' returns
446  # the widget's class, 'exists' checks if a private variable exists, and
447  # 'vars' returns a list of private variables. the latter allows to
448  # specify a pattern following the glob rules.
449  proc myinfo { sOption args } {
450    upvar this this
451    set sClass [lindex [bindtags $this] 1]
452
453    switch $sOption {
454      class {
455        set sClass
456      }
457
458      exists {
459        namespace eval ::$this info exists $args
460      }
461
462      vars {
463        set lVars {}
464        if { [llength $args] } {
465          set sPattern [lindex $args 0]
466        } else {
467          set sPattern *
468        }
469
470        foreach sVar [info vars ::${this}::$sPattern] {
471          lappend lVars [namespace tail $sVar]
472        }
473
474        set lVars
475      }
476
477      default {
478        error "Bad option '$sOption'. Must be class, exists, vars"
479      }
480    }
481  }
482
483  # name: our
484  # args: args: varname ?value?
485  # sets or retrieves a class-common variable. very similar to the set command.
486  # sets a variable in the namespace of the object's class.
487  proc our { args } {
488    upvar this this
489
490    set sClass [lindex [bindtags $this] 1]
491    namespace eval ::$sClass set $args
492  }
493
494  # name: unour
495  # args: args: list of class-common variables
496  # unsets class-common variables, just like the unset command.
497  proc unour { args } {
498    upvar this this
499    set sClass [lindex [bindtags $this] 1]
500    namespace eval ::$sClass "catch {unset $args}"
501  }
502
503  # name: ourarray
504  # args: args: anything allowed for the array command
505  # performs array operations on class-common arrays. maps to the array command.
506  proc ourarray { args } {
507    upvar this this
508    set sClass [lindex [bindtags $this] 1]
509    namespace eval ::$sClass array $args
510  }
511
512
513  # name: ourinfo
514  # args: sOption: exists, vars
515  #       args: depends on sOption
516  # provides information regarding class-common variables. 'exists' checks if
517  # a class-common variable exists, 'vars' returns a list of those variables.
518  # the latter allows to specify a pattern following the glob rules.
519  proc ourinfo { sOption args } {
520    upvar this this
521    set sClass [lindex [bindtags $this] 1]
522
523    switch $sOption {
524      exists {
525        namespace eval ::$sClass info exists $args
526      }
527
528      vars {
529        set lVars {}
530        if { [llength $args] } {
531          set sPattern [lindex $args 0]
532        } else {
533          set sPattern *
534        }
535
536        foreach sVar [info vars ::${sClass}::$sPattern] {
537          lappend lVars [namespace tail $sVar]
538        }
539
540        set lVars
541      }
542
543      default {
544        error "Bad option '$sOption'. Must be exists, vars"
545      }
546    }
547  }
548
549  # name: mkw.lextend
550  # args: lList: any tcl list
551  #       args: elements to append to list
552  # for each element in args, checks if it already exists in lList, and,
553  # if does not yet exist, appends it to lList. returns the new list.
554  proc mkw.lextend { lList args } {
555    foreach sArg $args {
556      if { [lsearch $lList $sArg] != -1 } continue
557      lappend lList $sArg
558    }
559
560    return $lList
561  }
562
563  # name: mkw.lshrink
564  # args: lList: any tcl list
565  #       args: elements to delete from list
566  # for each element in args, checks if it exists in lList, and,
567  # if it does, deletes it. returns the new list.
568  proc mkw.lshrink { lList args } {
569    foreach sArg $args {
570      set iPos [lsearch $lList $sArg]
571      if { $iPos == -1 } continue
572      set lList [lreplace $lList $iPos $iPos]
573    }
574
575    return $lList
576  }
577
578  # name: mkw.lchange
579  # args: lList: any tcl list
580  #       sOld: element to replace
581  #       sNew: new value to replace sOld with
582  # searches sOld in lList and replaces it with sNew. return the
583  # new list.
584  proc mkw.lchange { lList sOld sNew } {
585    set iPos [lsearch $lList $sOld]
586    if { $iPos != -1 } {
587      set lList [lreplace $lList $iPos $iPos $sNew]
588    }
589
590    return $lList
591  }
592
593  # name: mkw.lassign
594  # args: lList: any tcl list
595  #       args: list of variable names
596  # assigns the first element in lList to the variable specified with the
597  # first element in args, and so on. does not change remaining variables
598  # in args, if there are too few elements in lList.
599  proc mkw.lassign { lList args } {
600    set iMax [llength $lList]
601    set iCnt 0
602
603    foreach sElem $lList sVar $args {
604      if { $sVar == {} } break
605      uplevel [list set $sVar $sElem]
606
607      if { [incr iCnt] >= $iMax } break
608    }
609  }
610
611  # name: mkw.decode
612  # args: sValue: value to decode
613  #       lPairs: old/new value pairs
614  #       args: one element, the default value
615  # performs a mapping of values, similar to 'string map' (>= Tcl 8.1).
616  # searches sValue in the even-numbered elements of lPairs and
617  # returns the corresponding value (right next to a found match in
618  # lPairs). if sValue is not found, either returns sValue or any
619  # default value specified in args.
620  proc mkw.decode { sValue lPairs args } {
621    foreach { sMatch sRet } $lPairs {
622      if { $sMatch != $sValue } continue
623      return $sRet
624    }
625
626    if { [llength $args] } {
627      return [lindex $args 0]
628    } else {
629      return $sValue
630    }
631  }
632
633  # name: mkw.complete
634  # args: sShort: abbreviated name
635  #       lValues: list of full names
636  #       sWhat: text prefix for error message
637  # checks if sShort is a non-ambiguous abbreviation of any of the values
638  # in lValues and returns that value.
639  proc mkw.complete { sShort lValues {sWhat option}} {
640    foreach sValue $lValues {
641      set aTmp($sValue) {}
642    }
643
644    if { [info exists aTmp($sShort)] } {
645      return $sShort
646    } else {
647      set sLong [array names aTmp $sShort*]
648
649      if { [llength $sLong] == 1 } {
650        return $sLong
651      } elseif { [llength $sLong] == 0 } {
652        error "Bad $sWhat '$sShort': Must be [join $lValues ,]"
653      } else {
654        error "Ambiguous $sWhat '$sShort': Must be [join $lValues ,]"
655      }
656    }
657  }
658
659  # name: mkw.options
660  # args: lArgs: list of options or option-value pairs
661  #       args: list of option specifications
662  # a simple option processing routine. options can have no arguments (like
663  # with lsort -dictionary) or one argument (like fconfigure ... -blocking 1).
664  # lArgs is expected to consist of any combination of zero- or one-argument
665  # options, e.g. '-dictionary -command mySort -index 1 -decreasing'.
666  # allowed options are passed in args with option specifications. for options
667  # with no argument, the option specification is simply the name of the
668  # option, e.g. -dictionary. for options with a value, an option specification
669  # consists of two or three elements: the first is the option name, the second
670  # a list of allowed values or a * for any value. the third element is
671  # optional and specifies a default value if the option is not found in lArgs.
672  # for each option found, a variable with the same name as the option is set
673  # in the calling procedure's context. this variable's value is either a 1
674  # for options without argument, or the option's value. options can be
675  # abbreviated, as well as option values that map to a list of allowed values
676  # in the option specification. the command will return an error message
677  # if an unknown option was found, or, if one of the option specifications is
678  # a plain *, will return all elements in lArgs that could not be resolved.
679  proc mkw.options { lArgs args } {
680    # first store the option specifications in some arrays for fast access
681    foreach lSpec $args {
682      set iArgc [llength $lSpec]
683
684      if { $iArgc < 1 || $iArgc > 3 } {
685        error "Bad option spec '$lSpec': Must be name ?valuelist or *? ?defaultValue?"
686      }
687
688      set sOpt [lindex $lSpec 0]
689      set aOpt($sOpt) $iArgc
690      set aVal($sOpt) [lindex $lSpec 1]
691
692      # if default value is specified, set it right away
693      if { $iArgc == 3 } {
694        uplevel [list set $sOpt [lindex $lSpec 2]]
695      }
696    }
697
698    set lRest  {}            ;# remaining arguments not covered by option specs
699    set iArgc  [llength $lArgs]
700    set bAllow [info exists aOpt(*)]   ;# true if command shall not complain
701
702    # go through the option string and resolve
703    for { set i 0 } { $i < $iArgc } { incr i } {
704      set sOpt [lindex $lArgs $i]
705
706      # get defined options that match
707      if { [info exists aOpt($sOpt)] } {
708        set sOption $sOpt
709      } else {
710        set sOption [array names aOpt $sOpt*]
711      }
712
713      # resolve to exactly one option or complain or add to lRest
714      if { [llength $sOption] == 1 } {
715        if { $aOpt($sOption) == 1 } {
716          uplevel [list set $sOption 1]
717        } elseif { $aVal($sOpt) == "*" } {
718          incr i
719          uplevel [list set $sOption [lindex $lArgs $i]]
720        } else {
721          incr i
722          uplevel [list set $sOption [mkw.complete [lindex $lArgs $i] $aVal($sOpt) "option value"]]
723        }
724      } elseif { [llength $sOption] > 1 } {
725        error "Ambiguous option '$sOpt': Must be [join [array names aOpt] ,]"
726      } elseif { ! $bAllow } {
727        error "Bad option '$sOpt': Must be [join [array names aOpt] ,]"
728      } else {
729        lappend lRest $sOpt
730      }
731    }
732
733    return $lRest
734  }
735
736  # maintain a list of metawidgets defined so far
737  set lMetawidgets {}
738
739  # export metawidget command, the tool functions and the other stuff
740  namespace export metawidget mkw.* un* my* our*
741}
742
743# import the metawidget command
744namespace import ::metawidget::metawidget
745
Note: See TracBrowser for help on using the repository browser.