Error processing request

Parameters

CONTENT_LENGTH0
REQUEST_METHODGET
REQUEST_URI/revision/Measurement+widget+with+units+conversion?V=3
QUERY_STRINGV=3
CONTENT_TYPE
DOCUMENT_URI/revision/Measurement+widget+with+units+conversion
DOCUMENT_ROOT/var/www/nikit/nikit/nginx/../docroot
SCGI1
SERVER_PROTOCOLHTTP/1.1
HTTPSon
REMOTE_ADDR108.162.216.225
REMOTE_PORT39774
SERVER_PORT4443
SERVER_NAMEwiki.tcl-lang.org
HTTP_HOSTwiki.tcl-lang.org
HTTP_CONNECTIONKeep-Alive
HTTP_ACCEPT_ENCODINGgzip, br
HTTP_X_FORWARDED_FOR18.116.44.63
HTTP_CF_RAY88cc663c6d7c9126-ORD
HTTP_X_FORWARDED_PROTOhttps
HTTP_CF_VISITOR{"scheme":"https"}
HTTP_ACCEPT*/*
HTTP_USER_AGENTMozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; [email protected])
HTTP_REFERERhttp://wiki.tcl.tk/revision/Measurement+widget+with+units+conversion?V=3
HTTP_CF_CONNECTING_IP18.116.44.63
HTTP_CDN_LOOPcloudflare
HTTP_CF_IPCOUNTRYUS

Body


Error

Unknow state transition: LINE -> END

-code

1

-level

0

-errorstack

INNER {returnImm {Unknow state transition: LINE -> END} {}} CALL {my render_wikit {Measurement widget with units conversion} Based\ on\ the\ units\ converter\ I\ posted\ at\ \[unit\ converter\],\ here's\ a\ measurement\ widget.\ \ As\ always,\ feedback\ welcome.\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ --\[mailto:[email protected]\]\n\n----\n======\n\ #\ measurement.tcl\ --\n\ #\n\ #\ \ \ \ \ An\ entry\ widget\ which\ understands\ measurement\ units\n\ #\n\ #\n\ #\ Copyright\ 2000\ Pinebush\ Technologies\ Inc.\n\ #\n\ #\n\ #\ Exported\ procs:\n\ #\ \ \ \ \ measurement::measurement\ -\ Create\ a\ measurement\ widget\n\ #\n\ #\ A\ measurement\ widget\ is\ an\ enhanced\ entry\ widget\ that\ makes\ it\n\ #\ easier\ to\ get\ dimensions\ from\ user\ input.\ \ \n\ #\n\ #\ It\ supports\ separate\ display\ and\ reporting\ units\ so\ the\ user's\n\ #\ assumptions\ and\ the\ system's\ assuptions\ need\ not\ be\ the\ same.\ \ For\n\ #\ example,\ a\ measurement\ widget\ could\ be\ configure\ to\ assume\ the\ user\n\ #\ meant\ centimeters\ but\ that\ the\ system\ required\ inches.\ \ If\ the\ user\n\ #\ typed\ \"3.81\"\ into\ the\ widget,\ the\ textvariable\ associated\ with\ the\n\ #\ widget\ would\ have\ a\ value\ of\ \"1.5\".\n\ #\n\ #\ The\ user\ may\ enter\ explicit\ unit\ suffixes\ to\ override\ the\n\ #\ assumption.\ \ Continuing\ the\ previous\ example,\ if\ the\ user\ typed\n\ #\ \"54pt\"\ into\ the\ widget,\ the\ textvariable\ would\ be\ set\ to\ \".75\"\n\ #\n\ #\n\ #\ The\ measurement\ widget\ behaves\ like\ an\ entry\ except\ for\ the\ addition\n\ #\ of\ new\ options\ and\ subcommands\ as\ follows.\n\ #\n\ #\ Measurement\ widgets\ recognize\ the\ following\ additional\ options:\n\ #\n\ #\ \ \ \ \ -units\ :\ Specifies\ the\ implied\ units\ for\ the\ value\ stored\ in\ the\n\ #\ \ \ \ \ \ \ \ widget's\ textvariable\ and\ returned\ by\ the\ widget's\ get\n\ #\ \ \ \ \ \ \ \ command.\ The\ value\ of\ this\ option\ may\ be\ any\ unit\ string\n\ #\ \ \ \ \ \ \ \ recognized\ by\ the\ units\ package.\n\ #\n\ #\ \ \ \ \ -displayunits\ :\ Specifies\ the\ default\ units\ for\ the\ text\ displayed\n\ #\ \ \ \ \ \ \ \ in\ the\ widget.\ \ If\ the\ user\ does\ not\ type\ a\ unit\ suffix\ in\n\ #\ \ \ \ \ \ \ \ the\ entry,\ these\ units\ are\ assumed.\ \ The\ value\ of\ this\ option\n\ #\ \ \ \ \ \ \ \ may\ be\ any\ unit\ string\ recognized\ by\ the\ units\ package.\ If\n\ #\ \ \ \ \ \ \ \ not\ specified,\ displayunits\ defaults\ to\ the\ same\ value\ as\ units.\n\ #\n\ #\ \ \ \ \ -invalidforeground\ :\ Specifies\ a\ text\ color\ to\ use\ when\ the\n\ #\ \ \ \ \ \ \ \ contents\ of\ the\ widget\ are\ not\ a\ valid\ measurement.\ \ For\n\ #\ \ \ \ \ \ \ \ example,\ when\ the\ unit\ suffix\ is\ incomplete\ such\ as\ \"2.54c\"\n\ #\ \ \ \ \ \ \ \ on\ the\ way\ to\ typing\ \"2.54cm\".\ \ If\ not\ specified,\n\ #\ \ \ \ \ \ \ \ invalidforeground\ defaults\ to\ red.\n\ #\n\ #\ \ \ \ \ -invalidbackground\ :\ Specifies\ a\ background\ color\ to\ use\ when\n\ #\ \ \ \ \ \ \ \ the\ contents\ of\ the\ widget\ are\ not\ a\ valid\ measurement.\ \ If\n\ #\ \ \ \ \ \ \ \ not\ specified,\ invalidbackground\ defaults\ to\ the\ normal\n\ #\ \ \ \ \ \ \ \ background.\n\ #\n\ #\ Measurement\ widgets\ respond\ to\ the\ following\ additional\ or\ changed\n\ #\ commands:\n\ #\n\ #\ \ \ \ \ \ \$m\ get\ ?export?\ -\ Returns\ the\ value\ exported\ by\ the\ widget\ (the\n\ #\ \ \ \ \ \ \ \ \ same\ value\ that\ would\ be\ in\ the\ textvariable\ if\ one\ is\n\ #\ \ \ \ \ \ \ \ \ assigned).\ Raises\ an\ error\ if\ the\ text\ in\ the\ widget\ does\n\ #\ \ \ \ \ \ \ \ \ not\ represent\ a\ valid\ measurement.\n\ #\n\ #\ \ \ \ \ \ \$m\ get\ display\ -\ Returns\ the\ text\ shown\ to\ the\ user.\n\ #\n\ #\ \ \ \ \ \ \$m\ isvalid\ -\ Returns\ 1\ if\ \[\$m\ get\ export\]\ would\ raise\ an\ error,\n\ #\ \ \ \ \ \ \ \ \ 0\ otherwise.\n\ #\n\ #\ Also,\ trying\ to\ set\ the\ measurement\ widget's\ textvariable\ to\ a\ value\n\ #\ that\ does\ not\ represent\ a\ valid\ measurement\ raises\ an\ error.\n\ #\n\ #\n\ #\ WUZ\ -\ doesn't\ work\ with\ option\ database.\ Yet.\n\ #\n\ #\ Example:\n\ #\ \ \ \ \ See\ measurement::Test\ at\ the\ bottom\ of\ this\ file.\n\ #\n\ #\n\ #\ Global\ data:\n\ #\ \ \ \ \ None.\n\ #\n\ #-----------------------------------------------------------------------\n\n\ #\ package\ require\ units\n\ source\ units.tcl\n\n\ namespace\ eval\ ::measurement\ \{\n\ \ \ \ \ namespace\ export\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ meas\ \\\n\n\ \ \ \ \ #\ \"global\"\ array(s)\n\ \ \ \ \ variable\ Options\n\n\ \ \ \ \ #\ Some\ defaults\n\ \ \ \ \ set\ Options(-units)\ \"\"\n\ \ \ \ \ set\ Options(-invalidforeground)\ red\n\ \}\n\n\ #=======================================================================\n\ #\ Public\ procs\n\ #=======================================================================\n\ #\ measurement::measurement\ --\n\ #\n\ #\ \ \ \ \ Create\ a\ new\ widget\n\ #\ \n\ #\ Arguments:\n\ #\ \ \ \ \ \n\ #\ Results:\n\ #\ \ \ \ \ \n\ proc\ ::measurement::measurement\ \{\ w\ args\ \}\ \{\n\ \ \ \ \ variable\ Options\n\n\ \ \ \ \ #\ Create\ a\ namespace\ for\ the\ widget\n\ \ \ \ \ namespace\ eval\ \$w\ \{\}\n\n\ \ \ \ \ #\ The\ hull\ frame\n\ \ \ \ \ frame\ \$w\ -class\ Meas\n\n\ \ \ \ \ #\ Rename\ the\ widget\ command\ for\ the\ outer\ frame\ into\ the\ namespace\n\ \ \ \ \ #\ We\ never\ really\ use\ this\ command\ again.\n\ \ \ \ \ rename\ \$w\ measurement::\$\{w\}::frame\n\n\ \ \ \ \ #\ Make\ sure\ that\ closing\ this\ window\ does\ the\ right\ things.\n\ \ \ \ \ #\n\ \ \ \ \ #\ We\ bind\ to\ the\ Meas\ class\ rather\ than\ to\ the\ window\ because\n\ \ \ \ \ #\ the\ caller\ might\ bind\ to\ the\ window's\ destroy\ event\;\ the\ class\ is\n\ \ \ \ \ #\ *ours*,\ the\ window\ path\ is\ \"public\"\n\ \ \ \ \ bind\ Meas\ <Destroy>\ \[namespace\ code\ \[list\ Done\ %W\ CLOSE\]\]\n\n\n\ \ \ \ \ #========================================\n\ \ \ \ \ #\ Create\ the\ widget\n\ \ \ \ \ set\ e\ \[entry\ \$w.entry\]\n\ \ \ \ \ pack\ \$e\ -expand\ 1\ -fill\ both\n\n\ \ \ \ \ #\ Create\ a\ new\ widget\ command\n\ \ \ \ \ proc\ ::\$w\ \[info\ args\ measurement::WidgetProc\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \"set\ w\ \$w\;\[info\ body\ measurement::WidgetProc\]\"\n\n\ \ \ \ \ upvar\ ::measurement::\$\{w\}::options\ options\n\ \ \ \ \ set\ options(-units)\ \"\"\n\ \ \ \ \ set\ options(-invalidforeground)\ \$Options(-invalidforeground)\n\ \ \ \ \ set\ options(-invalidbackground)\ \[\$e\ cget\ -background\]\n\ \ \ \ \ set\ options(-validfg)\ \[\$e\ cget\ -foreground\]\n\ \ \ \ \ set\ options(-validbg)\ \[\$e\ cget\ -background\]\n\n\ \ \ \ \ \$w.entry\ configure\ -textvariable\ ::measurement::\$\{w\}::data(internalValue)\n\ \ \ \ \ trace\ variable\ ::measurement::\$\{w\}::data(internalValue)\ w\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[namespace\ code\ \[list\ UpdateExternalVar\ \$w\]\]\n\n\ \ \ \ \ #\ Pressing\ <Return>\ reformats\ to\ add\ units\n\ \ \ \ \ bind\ \$e\ <Return>\ \[namespace\ code\ \[list\ NormalizeValue\ \$w\]\]\n\n\ \ \ \ \ #\ Configure\ the\ widget\n\ \ \ \ \ if\ \{\[llength\ \$args\]\}\ \{\n\ \ \ \ \ \ \ \ \ eval\ \[list\ \$w\ configure\]\ \$args\n\ \ \ \ \ \}\n\n\ \ \ \ \ return\ \$w\n\ \}\n\ #\ measurement::measurement\n\ #\ \n\ #=======================================================================\n\ #\ Private\ procs\ only\ below\ this\ line\n\ #=======================================================================\n\ #\ measurement::Done\ --\n\ #\n\ #\ \ \ \ \ Clean\ up\ when\ the\ user's\ done\ with\ the\ option\ tree\n\ #\ \n\ #\ Arguments:\n\ #\ \ \ \ \ \n\ #\ Results:\n\ #\ \ \ \ \ Returns\ the\ number\ of\ changes\ made.\n\ #\n\ proc\ ::measurement::Done\ \{\ w\ why\ \}\ \{\n\ \ \ \ \ variable\ meas\n\n\ \ \ \ \ switch\ --\ \$why\ \{\n\ \ \ \ \ \ \ \ \ OK\ \{\n\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ CLOSE\ -\n\ \ \ \ \ \ \ \ \ CANCEL\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ delete\ measurement::\$w\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \}\n\ #\ measurement::Done\n\ #\ \n\ #-----------------------------------------------------------------------\n\ #\ measurement::WidgetProc\ --\n\ #\n\ #\ \ \ \ \ The\ widget\ proc\ for\ a\ measurement\ entry\;\ processes\ widget\ commands.\n\ #\ \n\ #\ Arguments:\n\ #\ \ \ \ \ \n\ #\ Results:\n\ #\ \ \ \ \ \n\ proc\ ::measurement::WidgetProc\ \{\ cmd\ args\ \}\ \{\n\ \ \ \ \ switch\ --\ \$cmd\ \{\n\ \ \ \ \ \ \ \ \ cget\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[measurement::Configure\ \$w\ \$args\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ lindex\ \$result\ 4\n\ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ configure\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ eval\ \[list\ measurement::Configure\ \$w\]\ \$args\n\ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ get\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ eval\ \[list\ measurement::Get\ \$w\]\ \$args\n\ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ isvalid\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ eval\ \[list\ measurement::IsValid\ \$w\]\ \$args\n\ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ default\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ #\ Pass\ the\ command\ down\ to\ the\ embedded\ entry\n\ \ \ \ \ \ \ \ \ \ \ \ \ eval\ \[list\ \$w.entry\ \$cmd\]\ \$args\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \}\n\ #\ measurement::WidgetProc\n\ #\ \n\ #-----------------------------------------------------------------------\n\ #\ measurement::Configure\ --\n\ #\n\ #\ \ \ \ \ Handle\ configure\ sub-command\ for\ widget.\n\ #\ \n\ #\ Arguments:\n\ #\ \ \ \ \ w\ \ \ \ -\ Path\ to\ the\ widget\n\ #\ \ \ \ \ args\ -\ Arguments\ to\ command\n\ #\n\ #\ Results:\n\ #\ \ \ \ \ \n\ proc\ ::measurement::Configure\ \{\ w\ args\}\ \{\n\ \ \ \ \ upvar\ ::measurement::\$\{w\}::options\ options\n\n\ \ \ \ \ #\ If\ 0\ args,\ get\ the\ full\ list\ from\ the\ base\ proc\ then\ post-process\n\ \ \ \ \ #\ \ \ \ wrapped\ commands\n\ \ \ \ \ #\ If\ 1\ arg,\ handle\ wrapped\ commands\ directly,\ ask\ base\ proc\ for\ others\n\ \ \ \ \ #\ If\ odd\ number\ of\ arguments,\ let\ the\ base\ proc\ generat\ the\ error\n\ \ \ \ \ #\ Otherwise,\ set\ options,\ checking\ for\ the\ ones\ we\ have\ to\ handle\ specially\n\ \ \ \ \ if\ \{\[llength\ \$args\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ #\ List\ all\ the\ entry's\ options\n\ \ \ \ \ \ \ \ \ set\ result\ \[eval\ \[list\ \$w.entry\ configure\]\ \$args\]\n\n\ \ \ \ \ \ \ \ \ #\ Remove\ entry's\ textvariable,\ we'll\ add\ our\ own\n\ \ \ \ \ \ \ \ \ set\ index\ \[lsearch\ -glob\ \$result\ \"-textvariable*\"\]\n\ \ \ \ \ \ \ \ \ set\ result\ \[lreplace\ \$result\ \$index\ \$index\]\n\n\ \ \ \ \ \ \ \ \ #\ Add\ our\ custom\ options,\ including\ textvariable\n\ \ \ \ \ \ \ \ \ foreach\ opt\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ -displayunits\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ -invalidforeground\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ -invalidbackground\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ -textvariable\n\ \ \ \ \ \ \ \ \ \ \ \ \ -units\ \n\ \ \ \ \ \ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ result\ \[Configure\ \$w\ \$opt\]\n\ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ #\ We\ added\ some\ things\ out\ of\ order\ at\ the\ end,\ so\ fix\ it\ up.\n\ \ \ \ \ \ \ \ \ lsort\ -index\ 0\ -dictionary\ \$result\n\ \ \ \ \ \}\ elseif\ \{\[llength\ \$args\]\ ==\ 1\ \}\ \{\n\ \ \ \ \ \ \ \ \ #\ Get\ the\ value\ for\ a\ single\ option\n\ \ \ \ \ \ \ \ \ set\ option\ \[lindex\ \$args\ 0\]\n\ \ \ \ \ \ \ \ \ switch\ --\ \$option\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ -units\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[list\ -units\ units\ Units\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\"\ \$options(\$option)\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ -displayunits\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[list\ -displayunits\ displayUnits\ DisplayUnits\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\"\ \$options(\$option)\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ -invalidforeground\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[list\ -invalidforeground\ invalidForeground\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ InvalidForeground\ \"\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$options(\$option)\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ -invalidbackground\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[list\ -invalidbackground\ invalidBackground\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ InvalidBackground\ \"\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$options(\$option)\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ -textvariable\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Get\ the\ name,\ defaults,\ etc.\ from\ entry\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[eval\ \[list\ \$w.entry\ configure\]\ \$args\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Put\ the\ real\ user's\ value\ in,\ not\ our\ wrapper\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ options(-textvariable)\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textVar\ \$options(-textvariable)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textVar\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lreplace\ \$result\ 4\ 4\ \$textVar\n\ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ default\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ eval\ \[list\ \$w.entry\ configure\]\ \$args\n\ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\ elseif\ \{\[llength\ \$args\]%2\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ #\ Odd\ number\ >\ 1,\ let\ the\ entry\ complain\n\ \ \ \ \ \ \ \ \ eval\ \[list\ \$w.entry\ configure\]\ \$args\n\ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ #\ Even\ number,\ set\ a\ bunch\ of\ option\ values\n\ \ \ \ \ \ \ \ \ array\ set\ opt\ \$args\n\ \ \ \ \ \ \ \ \ foreach\ option\ \[array\ names\ opt\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ switch\ --\ \$option\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -units\ -\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -displayunits\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ units\ \$opt(\$option)\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ An\ empty\ string\ means\ no\ conversion\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Normalize\ any\ non-empty\ unit\ string\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[string\ length\ \$units\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ units\ \[units::normalize\ \$units\]\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ options(\$option)\ \$units\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ unset\ opt(\$option)\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[string\ equal\ \$option\ -units\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ UpdateExternalVar\ \$w\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ UpdateInternalVar\ \$w\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -invalidforeground\ -\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -invalidbackground\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ options(\$option)\ \$opt(\$option)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ unset\ opt(\$option)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -textvariable\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ varName\ \"::\$opt(\$option)\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Remember\ what\ the\ user\ wanted.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ options(-textvariable)\ \$varName\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Put\ a\ read\ trace\ on\ the\ user's\ variable\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ to\ raise\ an\ error\ when\ reading\ a\ variable\ from\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ an\ inconsistent\ measurement.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ trace\ variable\ \$varName\ r\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[namespace\ code\ \[list\ ValidateRead\ \$w\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Put\ a\ write\ trace\ on\ the\ user's\ variable\ to\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ update\ the\ widget\ internal\ variable\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ trace\ variable\ \$varName\ w\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[namespace\ code\ \[list\ UpdateInternalVar\ \$w\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Set\ measurement\ from\ user\ var\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ \$varName\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ UpdateInternalVar\ \$w\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ We\ always\ have\ our\ own\ text\ variable\ set\ so\ just\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ unset\ this.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ unset\ opt(\$option)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ #\ foreach\n\n\ \ \ \ \ \ \ \ \ if\ \{\[array\ size\ opt\]\ !=\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ eval\ \[list\ \$w.entry\ configure\]\ \[array\ get\ opt\]\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \ \ \ #\ if\n\ \}\n\ #\ measurement::Configure\n\ #\ \n\ #-----------------------------------------------------------------------\n\ #\ measurement::UpdateExternalVar\ --\n\ #\n\ #\ \ \ \ \ Update\ the\ external\ variable\ when\ the\ user\ modifies\ the\n\ #\ \ \ \ \ measurement.\n\ #\ \n\ #\ Arguments:\n\ #\ \ \ \ \ \n\ #\ Results:\n\ #\ \ \ \ \ \n\ proc\ ::measurement::UpdateExternalVar\ \{\ w\ args\ \}\ \{\n\ \ \ \ \ upvar\ ::measurement::\$\{w\}::options\ options\n\ \ \ \ \ upvar\ ::measurement::\$\{w\}::data\ data\n\n\ \ \ \ \ if\ \{\[info\ exists\ measurement::InUpdate\]\}\ \{\n\ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \}\n\ \ \ \ \ set\ measurement::InUpdate\ 1\n\n\ \ \ \ \ set\ units\ \$options(-units)\n\ \ \ \ \ if\ \{\[info\ exists\ options(-displayunits)\]\}\ \{\n\ \ \ \ \ \ \ \ \ set\ displayunits\ \$options(-displayunits)\n\ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ set\ displayunits\ \$options(-units)\n\ \ \ \ \ \}\n\n\ \ \ \ \ set\ valueIn\ \$data(internalValue)\n\n\ \ \ \ \ if\ \{\[string\ length\ \$valueIn\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ set\ valueOut\ \$valueIn\n\ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ if\ \{\[catch\ \{units::parse\ \$valueIn\}\ meaIn\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$w.entry\ configure\ -foreground\ \$options(-invalidforeground)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$w.entry\ configure\ -background\ \$options(-invalidbackground)\n\ \ \ \ \ \ \ \ \ \ \ \ \ unset\ measurement::InUpdate\n\ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$meaIn\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ meaIn\ \$displayunits\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ if\ \{\[catch\ \{units::convert\ \$meaIn\ \$units\}\ meaOut\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$w.entry\ configure\ -foreground\ \$options(-invalidforeground)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$w.entry\ configure\ -background\ \$options(-invalidbackground)\n\ \ \ \ \ \ \ \ \ \ \ \ \ unset\ measurement::InUpdate\n\ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ set\ valueOut\ \[lindex\ \$meaOut\ 0\]\n\ \ \ \ \ \}\n\n\ \ \ \ \ \$w.entry\ configure\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ -foreground\ \$options(-validfg)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ -background\ \$options(-validbg)\n\n\ \ \ \ \ #\ Set\ the\ user's\ variable,\ if\ there\ is\ one\n\ \ \ \ \ if\ \{\[info\ exists\ options(-textvariable)\]\}\ \{\n\ \ \ \ \ \ \ \ \ set\ \$options(-textvariable)\ \$valueOut\n\ \ \ \ \ \}\n\ \ \ \ \ unset\ measurement::InUpdate\n\ \}\n\ #\ measurement::UpdateExternalVar\n\ #\ \n\ #-----------------------------------------------------------------------\n\ #\ measurement::UpdateInternalVar\ --\n\ #\n\ #\ \ \ \ \ Update\ the\ internal\ variable\ which\ is\ tied\ to\ the\ text\ the\ user\n\ #\ \ \ \ \ sees.\n\ #\ \n\ #\ Arguments:\n\ #\ \ \ \ \ \n\ #\ Results:\n\ #\ \ \ \ \ \n\ proc\ ::measurement::UpdateInternalVar\ \{\ w\ args\ \}\ \{\n\ \ \ \ \ upvar\ ::measurement::\$\{w\}::options\ options\n\ \ \ \ \ upvar\ ::measurement::\$\{w\}::data\ data\n\n\ \ \ \ \ if\ \{\[info\ exists\ measurement::InUpdate\]\}\ \{\n\ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \}\n\ \ \ \ \ set\ measurement::InUpdate\ 1\n\n\ \ \ \ \ set\ units\ \$options(-units)\n\n\ \ \ \ \ #\ Get\ the\ variable\ name\n\ \ \ \ \ set\ varName\ \$options(-textvariable)\n\n\ \ \ \ \ if\ \{\[info\ exists\ \$varName\]\}\ \{\n\ \ \ \ \ \ \ \ \ #\ Get\ the\ external\ value\n\ \ \ \ \ \ \ \ \ set\ valueIn\ \[set\ ::\$varName\]\n\ \ \ \ \ \ \ \ \ if\ \{\[string\ length\ \$valueIn\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[catch\ \{units::parse\ \$valueIn\}\ meaIn\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Restore\ the\ last,\ valid\ external\ value.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ \$varName\ \$data(externalValue)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Clear\ our\ semaphore\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ unset\ measurement::InUpdate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Raise\ an\ error.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"'\$valueIn'\ cannot\ be\ parsed\ for\ units\ conversion\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ #\ Now\ that\ it's\ valid,\ save\ it\ for\ later\n\ \ \ \ \ \ \ \ \ \ \ \ \ set\ data(externalValue)\ \$valueIn\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ #\ If\ there\ was\ no\ unit\ in\ the\ external\ variable,\ add\ one.\n\ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$meaIn\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ meaIn\ \$units\n\ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ #\ Update\ the\ measurement\n\ \ \ \ \ \ \ \ \ \ \ \ \ set\ data(internalValue)\ \[join\ \$meaIn\ \"\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ NormalizeValue\ \$w\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \ \ \ unset\ measurement::InUpdate\n\ \}\n\ #\ measurement::UpdateInternalVar\n\ #\ \n\ #-----------------------------------------------------------------------\n\ #\ measurement::NormalizeValue\ --\n\ #\n\ #\ \ \ \ \ Normalize\ the\ value\ displayed,\ include\ units,\ etc.\n\ #\ \n\ #\ Arguments:\n\ #\ \ \ \ \ \n\ #\ Results:\n\ #\ \ \ \ \ \n\ proc\ ::measurement::NormalizeValue\ \{\ w\ \}\ \{\n\ \ \ \ \ upvar\ ::measurement::\$\{w\}::options\ options\n\ \ \ \ \ upvar\ ::measurement::\$\{w\}::data\ data\n\n\ \ \ \ \ #\ Get\ the\ default\ units\ for\ this\ measurement\n\ \ \ \ \ if\ \{\[info\ exists\ options(-displayunits)\]\}\ \{\n\ \ \ \ \ \ \ \ \ set\ units\ \$options(-displayunits)\n\ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ set\ units\ \$options(-units)\n\ \ \ \ \ \}\n\n\ \ \ \ \ #\ Get\ the\ current\ value\n\ \ \ \ \ set\ valueIn\ \$data(internalValue)\n\ \ \ \ \ #\ If\ we\ can't\ parse\ the\ current\ value,\ give\ up.\n\ \ \ \ \ if\ \{\ \[catch\ \{units::parse\ \$valueIn\}\ meaIn\]\ \}\ \{\n\ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \}\n\ \ \ \ \ #\ If\ there\ aren't\ units\ in\ the\ current\ value,\ use\ the\ default\n\ \ \ \ \ if\ \{\[llength\ \$meaIn\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ lappend\ meaIn\ \$units\n\ \ \ \ \ \}\n\n\ \ \ \ \ #\ Convert\ to\ expected\ units\n\ \ \ \ \ set\ meaOut\ \[units::convert\ \$meaIn\ \$units\]\n\ \ \ \ \ set\ valueOut\ \[join\ \$meaOut\ \"\"\]\n\n\ \ \ \ \ #\ Update\ the\ display\ with\ the\ normalized\ value.\n\ \ \ \ \ set\ data(internalValue)\ \$valueOut\n\ \}\n\ #\ measurement::NormalizeValue\n\ #\ \n\ #-----------------------------------------------------------------------\n\ #\ measurement::Get\ --\n\ #\n\ #\ \ \ \ \ Get\ the\ value\ of\ the\ widget\n\ #\ \n\ #\ Arguments:\n\ #\ \ \ \ \ w\ \ \ \ -\ The\ measurement\ widget\n\ #\ \ \ \ \ what\ -\ What\ to\ return,\ \"export\"\ (the\ textvariable\ value)\ or\n\ #\ \ \ \ \ \ \ \ \ \ \ \ \"display\"\ (what\ the\ user\ typed\ and\ sees).\ \ export\ is\ the\n\ #\ \ \ \ \ \ \ \ \ \ \ \ default.\n\ #\n\ #\ Results:\n\ #\ \ \ \ \ Returns\ the\ value\ of\ the\ widget.\n\ #\n\ proc\ measurement::Get\ \{\ w\ \{what\ \"export\"\}\ \}\ \{\n\ \ \ \ \ upvar\ ::measurement::\$\{w\}::data\ data\n\ \ \ \ \ switch\ --\ \$what\ \{\n\ \ \ \ \ \ \ \ \ display\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \$data(internalValue)\n\ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ export\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ #\ Raise\ an\ error\ if\ inconsistent\n\ \ \ \ \ \ \ \ \ \ \ \ \ set\ result\ foo\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ default\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"Invalid\ option,\ '\$what'\;\ must\ be\ display\ or\ export\"\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \ \ \ return\ \$result\n\ \}\n\ #\ measurement::Get\n\ #\ \n\ #-----------------------------------------------------------------------\n\ #\ measurement::IsValid\ --\n\ #\n\ #\ \ \ \ \ Make\ sure\ that\ the\ text\ typed\ by\ the\ user\ is\ valid\ and\ that\ the\n\ #\ \ \ \ \ value\ reported\ by\ \[\$m\ get\ export\]\ and\ \[\$m\ get\ display\]\ are\n\ #\ \ \ \ \ consistent.\n\ #\ \n\ #\ Arguments:\n\ #\ \ \ \ \ w\ -\ The\ measurement\ widget.\n\ #\n\ #\ Results:\n\ #\ \ \ \ \ Returns\ 1\ if\ the\ text\ is\ valid\ and\ the\ internal\ and\ external\n\ #\ \ \ \ \ values\ are\ consistent,\ 0\ otherwise.\n\ #\n\ proc\ measurement::IsValid\ \{\ w\ \}\ \{\n\ \ \ \ \ upvar\ ::measurement::\$\{w\}::data\ data\n\n\ \ \ \ \ #\ If\ we\ can't\ parse\ the\ current\ value,\ it's\ invalid\n\ \ \ \ \ if\ \{\[catch\ \{units::parse\ \$data(internalValue)\}\]\}\ \{\n\ \ \ \ \ \ \ \ \ return\ 0\n\ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ return\ 1\n\ \ \ \ \ \}\n\ \}\n\ #\ measurement::IsValid\n\ #\ \n\ #-----------------------------------------------------------------------\n\ #\ measurement::ValidateRead\ --\n\ #\n\ #\ \ \ \ \ <short\ description>\n\ #\ \n\ #\ Arguments:\n\ #\ \ \ \ \ \n\ #\ Results:\n\ #\ \ \ \ \ \n\ proc\ measurement::ValidateRead\ \{\ w\ args\ \}\ \{\n\ \ \ \ \ upvar\ ::measurement::\$\{w\}::data\ data\n\ \ \ \ \ if\ \{\ !\ \[IsValid\ \$w\]\ \}\ \{\n\ \ \ \ \ \ \ \ \ error\ \"'\$data(internalValue)'\ cannot\ be\ parsed\ for\ units\ conversion\"\n\ \ \ \ \ \}\n\ \}\n\ #\ measurement::ValidateRead\n\ #\ \n\ #-----------------------------------------------------------------------\n\ #\ measurement::Test\ --\n\ #\n\ #\ \ \ \ \ <short\ description>\n\ #\ \n\ #\ Arguments:\n\ #\ \ \ \ \ \n\ #\ Results:\n\ #\ \ \ \ \ \n\ proc\ ::measurement::Test\ \{\ \{w\ \"\"\}\ \}\ \{\n\ \ \ \ \ #\ Just\ in\ case.\n\ \ \ \ \ destroy\ \$w.test\n\n\ \ \ \ \ set\ f\ \[frame\ \$w.test\]\n\ \ \ \ \ pack\ \$f\n\n\ \ \ \ \ set\ ::edit\ cm\n\ \ \ \ \ set\ ::show\ cm\n\n\ \ \ \ \ frame\ \$f.top\n\ \ \ \ \ pack\ \$f.top\ -side\ top\ -expand\ 1\ -fill\ both\ -padx\ 2m\ -pady\ 2m\n\ \ \ \ \ label\ \$f.top.label\ -text\ \"Input:\"\n\ \ \ \ \ pack\ \$f.top.label\ -side\ left\ \n\ \ \ \ \ measurement\ \$f.top.entry\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ -units\ \$::edit\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ -displayunits\ \$::show\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ -textvariable\ foo\n\ \ \ \ \ \$f.top.entry\ configure\ -invalidforeground\ red\n\ \ \ \ \ pack\ \$f.top.entry\ -side\ left\ -expand\ 1\ -fill\ x\n\n\ \ \ \ \ frame\ \$f.edit\n\ \ \ \ \ pack\ \$f.edit\ -side\ top\ -expand\ 1\ -fill\ both\ -padx\ 2m\ -pady\ 2m\n\ \ \ \ \ label\ \$f.edit.label\ -text\ \"Edit\ in:\"\ -width\ 10\n\ \ \ \ \ pack\ \$f.edit.label\ -side\ left\n\ \ \ \ \ foreach\ unit\ \{pt\ cm\ in\ ft\}\ \{\n\ \ \ \ \ \ \ \ \ radiobutton\ \$f.edit.\$unit\ -text\ \$unit\ -width\ 3\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -command\ \[list\ \$f.top.entry\ configure\ -displayunits\ \$unit\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -variable\ edit\ -value\ \$unit\n\ \ \ \ \ \ \ \ \ pack\ \$f.edit.\$unit\ -side\ left\n\ \ \ \ \ \}\n\n\ \ \ \ \ frame\ \$f.show\n\ \ \ \ \ pack\ \$f.show\ -side\ top\ -expand\ 1\ -fill\ both\ -padx\ 2m\ -pady\ 2m\n\ \ \ \ \ label\ \$f.show.label\ -text\ \"Export\ in:\"\ -width\ 10\n\ \ \ \ \ pack\ \$f.show.label\ -side\ left\n\ \ \ \ \ foreach\ unit\ \{pt\ cm\ in\ ft\}\ \{\n\ \ \ \ \ \ \ \ \ radiobutton\ \$f.show.\$unit\ -text\ \$unit\ -width\ 3\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -command\ \[list\ \$f.top.entry\ configure\ -units\ \$unit\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -variable\ show\ -value\ \$unit\n\ \ \ \ \ \ \ \ \ pack\ \$f.show.\$unit\ -side\ left\n\ \ \ \ \ \}\n\n\ \ \ \ \ frame\ \$f.btm\n\ \ \ \ \ pack\ \$f.btm\ -side\ top\ -expand\ 1\ -fill\ both\ -padx\ 2m\ -pady\ 2m\n\ \ \ \ \ label\ \$f.btm.label\ -textvariable\ show\n\ \ \ \ \ pack\ \$f.btm.label\ -side\ left\ \n\ \ \ \ \ entry\ \$f.btm.entry\ -textvariable\ foo\n\ \ \ \ \ pack\ \$f.btm.entry\ -side\ left\ -expand\ 1\ -fill\ x\n\ \}\n\ #\ measurement::Test\n\ #\ \n\n\ #\ Make\ it\ easier\ to\ create\ measurement\ widgets\n\ namespace\ import\ measurement::measurement\n\n======\n\n\[ARR\]:\ Hi,\ I\ like\ to\ test\ this\ out.\ Where\ can\ I\ find\ the\ units.tcl\ file?\ I\ tried\ 'package\ req\ units'\ in\ my\ ActiveTcl\ 8.5\ but\ the\ proc\ 'units::normalize'\ is\ not\ there.\n\n======\n\n<<categories>>\ GUI regexp2} CALL {my render {Measurement widget with units conversion} Based\ on\ the\ units\ converter\ I\ posted\ at\ \[unit\ converter\],\ here's\ a\ measurement\ widget.\ \ As\ always,\ feedback\ welcome.\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ --\[mailto:[email protected]\]\n\n----\n======\n\ #\ measurement.tcl\ --\n\ #\n\ #\ \ \ \ \ An\ entry\ widget\ which\ understands\ measurement\ units\n\ #\n\ #\n\ #\ Copyright\ 2000\ Pinebush\ Technologies\ Inc.\n\ #\n\ #\n\ #\ Exported\ procs:\n\ #\ \ \ \ \ measurement::measurement\ -\ Create\ a\ measurement\ widget\n\ #\n\ #\ A\ measurement\ widget\ is\ an\ enhanced\ entry\ widget\ that\ makes\ it\n\ #\ easier\ to\ get\ dimensions\ from\ user\ input.\ \ \n\ #\n\ #\ It\ supports\ separate\ display\ and\ reporting\ units\ so\ the\ user's\n\ #\ assumptions\ and\ the\ system's\ assuptions\ need\ not\ be\ the\ same.\ \ For\n\ #\ example,\ a\ measurement\ widget\ could\ be\ configure\ to\ assume\ the\ user\n\ #\ meant\ centimeters\ but\ that\ the\ system\ required\ inches.\ \ If\ the\ user\n\ #\ typed\ \"3.81\"\ into\ the\ widget,\ the\ textvariable\ associated\ with\ the\n\ #\ widget\ would\ have\ a\ value\ of\ \"1.5\".\n\ #\n\ #\ The\ user\ may\ enter\ explicit\ unit\ suffixes\ to\ override\ the\n\ #\ assumption.\ \ Continuing\ the\ previous\ example,\ if\ the\ user\ typed\n\ #\ \"54pt\"\ into\ the\ widget,\ the\ textvariable\ would\ be\ set\ to\ \".75\"\n\ #\n\ #\n\ #\ The\ measurement\ widget\ behaves\ like\ an\ entry\ except\ for\ the\ addition\n\ #\ of\ new\ options\ and\ subcommands\ as\ follows.\n\ #\n\ #\ Measurement\ widgets\ recognize\ the\ following\ additional\ options:\n\ #\n\ #\ \ \ \ \ -units\ :\ Specifies\ the\ implied\ units\ for\ the\ value\ stored\ in\ the\n\ #\ \ \ \ \ \ \ \ widget's\ textvariable\ and\ returned\ by\ the\ widget's\ get\n\ #\ \ \ \ \ \ \ \ command.\ The\ value\ of\ this\ option\ may\ be\ any\ unit\ string\n\ #\ \ \ \ \ \ \ \ recognized\ by\ the\ units\ package.\n\ #\n\ #\ \ \ \ \ -displayunits\ :\ Specifies\ the\ default\ units\ for\ the\ text\ displayed\n\ #\ \ \ \ \ \ \ \ in\ the\ widget.\ \ If\ the\ user\ does\ not\ type\ a\ unit\ suffix\ in\n\ #\ \ \ \ \ \ \ \ the\ entry,\ these\ units\ are\ assumed.\ \ The\ value\ of\ this\ option\n\ #\ \ \ \ \ \ \ \ may\ be\ any\ unit\ string\ recognized\ by\ the\ units\ package.\ If\n\ #\ \ \ \ \ \ \ \ not\ specified,\ displayunits\ defaults\ to\ the\ same\ value\ as\ units.\n\ #\n\ #\ \ \ \ \ -invalidforeground\ :\ Specifies\ a\ text\ color\ to\ use\ when\ the\n\ #\ \ \ \ \ \ \ \ contents\ of\ the\ widget\ are\ not\ a\ valid\ measurement.\ \ For\n\ #\ \ \ \ \ \ \ \ example,\ when\ the\ unit\ suffix\ is\ incomplete\ such\ as\ \"2.54c\"\n\ #\ \ \ \ \ \ \ \ on\ the\ way\ to\ typing\ \"2.54cm\".\ \ If\ not\ specified,\n\ #\ \ \ \ \ \ \ \ invalidforeground\ defaults\ to\ red.\n\ #\n\ #\ \ \ \ \ -invalidbackground\ :\ Specifies\ a\ background\ color\ to\ use\ when\n\ #\ \ \ \ \ \ \ \ the\ contents\ of\ the\ widget\ are\ not\ a\ valid\ measurement.\ \ If\n\ #\ \ \ \ \ \ \ \ not\ specified,\ invalidbackground\ defaults\ to\ the\ normal\n\ #\ \ \ \ \ \ \ \ background.\n\ #\n\ #\ Measurement\ widgets\ respond\ to\ the\ following\ additional\ or\ changed\n\ #\ commands:\n\ #\n\ #\ \ \ \ \ \ \$m\ get\ ?export?\ -\ Returns\ the\ value\ exported\ by\ the\ widget\ (the\n\ #\ \ \ \ \ \ \ \ \ same\ value\ that\ would\ be\ in\ the\ textvariable\ if\ one\ is\n\ #\ \ \ \ \ \ \ \ \ assigned).\ Raises\ an\ error\ if\ the\ text\ in\ the\ widget\ does\n\ #\ \ \ \ \ \ \ \ \ not\ represent\ a\ valid\ measurement.\n\ #\n\ #\ \ \ \ \ \ \$m\ get\ display\ -\ Returns\ the\ text\ shown\ to\ the\ user.\n\ #\n\ #\ \ \ \ \ \ \$m\ isvalid\ -\ Returns\ 1\ if\ \[\$m\ get\ export\]\ would\ raise\ an\ error,\n\ #\ \ \ \ \ \ \ \ \ 0\ otherwise.\n\ #\n\ #\ Also,\ trying\ to\ set\ the\ measurement\ widget's\ textvariable\ to\ a\ value\n\ #\ that\ does\ not\ represent\ a\ valid\ measurement\ raises\ an\ error.\n\ #\n\ #\n\ #\ WUZ\ -\ doesn't\ work\ with\ option\ database.\ Yet.\n\ #\n\ #\ Example:\n\ #\ \ \ \ \ See\ measurement::Test\ at\ the\ bottom\ of\ this\ file.\n\ #\n\ #\n\ #\ Global\ data:\n\ #\ \ \ \ \ None.\n\ #\n\ #-----------------------------------------------------------------------\n\n\ #\ package\ require\ units\n\ source\ units.tcl\n\n\ namespace\ eval\ ::measurement\ \{\n\ \ \ \ \ namespace\ export\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ meas\ \\\n\n\ \ \ \ \ #\ \"global\"\ array(s)\n\ \ \ \ \ variable\ Options\n\n\ \ \ \ \ #\ Some\ defaults\n\ \ \ \ \ set\ Options(-units)\ \"\"\n\ \ \ \ \ set\ Options(-invalidforeground)\ red\n\ \}\n\n\ #=======================================================================\n\ #\ Public\ procs\n\ #=======================================================================\n\ #\ measurement::measurement\ --\n\ #\n\ #\ \ \ \ \ Create\ a\ new\ widget\n\ #\ \n\ #\ Arguments:\n\ #\ \ \ \ \ \n\ #\ Results:\n\ #\ \ \ \ \ \n\ proc\ ::measurement::measurement\ \{\ w\ args\ \}\ \{\n\ \ \ \ \ variable\ Options\n\n\ \ \ \ \ #\ Create\ a\ namespace\ for\ the\ widget\n\ \ \ \ \ namespace\ eval\ \$w\ \{\}\n\n\ \ \ \ \ #\ The\ hull\ frame\n\ \ \ \ \ frame\ \$w\ -class\ Meas\n\n\ \ \ \ \ #\ Rename\ the\ widget\ command\ for\ the\ outer\ frame\ into\ the\ namespace\n\ \ \ \ \ #\ We\ never\ really\ use\ this\ command\ again.\n\ \ \ \ \ rename\ \$w\ measurement::\$\{w\}::frame\n\n\ \ \ \ \ #\ Make\ sure\ that\ closing\ this\ window\ does\ the\ right\ things.\n\ \ \ \ \ #\n\ \ \ \ \ #\ We\ bind\ to\ the\ Meas\ class\ rather\ than\ to\ the\ window\ because\n\ \ \ \ \ #\ the\ caller\ might\ bind\ to\ the\ window's\ destroy\ event\;\ the\ class\ is\n\ \ \ \ \ #\ *ours*,\ the\ window\ path\ is\ \"public\"\n\ \ \ \ \ bind\ Meas\ <Destroy>\ \[namespace\ code\ \[list\ Done\ %W\ CLOSE\]\]\n\n\n\ \ \ \ \ #========================================\n\ \ \ \ \ #\ Create\ the\ widget\n\ \ \ \ \ set\ e\ \[entry\ \$w.entry\]\n\ \ \ \ \ pack\ \$e\ -expand\ 1\ -fill\ both\n\n\ \ \ \ \ #\ Create\ a\ new\ widget\ command\n\ \ \ \ \ proc\ ::\$w\ \[info\ args\ measurement::WidgetProc\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \"set\ w\ \$w\;\[info\ body\ measurement::WidgetProc\]\"\n\n\ \ \ \ \ upvar\ ::measurement::\$\{w\}::options\ options\n\ \ \ \ \ set\ options(-units)\ \"\"\n\ \ \ \ \ set\ options(-invalidforeground)\ \$Options(-invalidforeground)\n\ \ \ \ \ set\ options(-invalidbackground)\ \[\$e\ cget\ -background\]\n\ \ \ \ \ set\ options(-validfg)\ \[\$e\ cget\ -foreground\]\n\ \ \ \ \ set\ options(-validbg)\ \[\$e\ cget\ -background\]\n\n\ \ \ \ \ \$w.entry\ configure\ -textvariable\ ::measurement::\$\{w\}::data(internalValue)\n\ \ \ \ \ trace\ variable\ ::measurement::\$\{w\}::data(internalValue)\ w\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[namespace\ code\ \[list\ UpdateExternalVar\ \$w\]\]\n\n\ \ \ \ \ #\ Pressing\ <Return>\ reformats\ to\ add\ units\n\ \ \ \ \ bind\ \$e\ <Return>\ \[namespace\ code\ \[list\ NormalizeValue\ \$w\]\]\n\n\ \ \ \ \ #\ Configure\ the\ widget\n\ \ \ \ \ if\ \{\[llength\ \$args\]\}\ \{\n\ \ \ \ \ \ \ \ \ eval\ \[list\ \$w\ configure\]\ \$args\n\ \ \ \ \ \}\n\n\ \ \ \ \ return\ \$w\n\ \}\n\ #\ measurement::measurement\n\ #\ \n\ #=======================================================================\n\ #\ Private\ procs\ only\ below\ this\ line\n\ #=======================================================================\n\ #\ measurement::Done\ --\n\ #\n\ #\ \ \ \ \ Clean\ up\ when\ the\ user's\ done\ with\ the\ option\ tree\n\ #\ \n\ #\ Arguments:\n\ #\ \ \ \ \ \n\ #\ Results:\n\ #\ \ \ \ \ Returns\ the\ number\ of\ changes\ made.\n\ #\n\ proc\ ::measurement::Done\ \{\ w\ why\ \}\ \{\n\ \ \ \ \ variable\ meas\n\n\ \ \ \ \ switch\ --\ \$why\ \{\n\ \ \ \ \ \ \ \ \ OK\ \{\n\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ CLOSE\ -\n\ \ \ \ \ \ \ \ \ CANCEL\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ delete\ measurement::\$w\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \}\n\ #\ measurement::Done\n\ #\ \n\ #-----------------------------------------------------------------------\n\ #\ measurement::WidgetProc\ --\n\ #\n\ #\ \ \ \ \ The\ widget\ proc\ for\ a\ measurement\ entry\;\ processes\ widget\ commands.\n\ #\ \n\ #\ Arguments:\n\ #\ \ \ \ \ \n\ #\ Results:\n\ #\ \ \ \ \ \n\ proc\ ::measurement::WidgetProc\ \{\ cmd\ args\ \}\ \{\n\ \ \ \ \ switch\ --\ \$cmd\ \{\n\ \ \ \ \ \ \ \ \ cget\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[measurement::Configure\ \$w\ \$args\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ lindex\ \$result\ 4\n\ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ configure\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ eval\ \[list\ measurement::Configure\ \$w\]\ \$args\n\ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ get\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ eval\ \[list\ measurement::Get\ \$w\]\ \$args\n\ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ isvalid\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ eval\ \[list\ measurement::IsValid\ \$w\]\ \$args\n\ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ default\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ #\ Pass\ the\ command\ down\ to\ the\ embedded\ entry\n\ \ \ \ \ \ \ \ \ \ \ \ \ eval\ \[list\ \$w.entry\ \$cmd\]\ \$args\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \}\n\ #\ measurement::WidgetProc\n\ #\ \n\ #-----------------------------------------------------------------------\n\ #\ measurement::Configure\ --\n\ #\n\ #\ \ \ \ \ Handle\ configure\ sub-command\ for\ widget.\n\ #\ \n\ #\ Arguments:\n\ #\ \ \ \ \ w\ \ \ \ -\ Path\ to\ the\ widget\n\ #\ \ \ \ \ args\ -\ Arguments\ to\ command\n\ #\n\ #\ Results:\n\ #\ \ \ \ \ \n\ proc\ ::measurement::Configure\ \{\ w\ args\}\ \{\n\ \ \ \ \ upvar\ ::measurement::\$\{w\}::options\ options\n\n\ \ \ \ \ #\ If\ 0\ args,\ get\ the\ full\ list\ from\ the\ base\ proc\ then\ post-process\n\ \ \ \ \ #\ \ \ \ wrapped\ commands\n\ \ \ \ \ #\ If\ 1\ arg,\ handle\ wrapped\ commands\ directly,\ ask\ base\ proc\ for\ others\n\ \ \ \ \ #\ If\ odd\ number\ of\ arguments,\ let\ the\ base\ proc\ generat\ the\ error\n\ \ \ \ \ #\ Otherwise,\ set\ options,\ checking\ for\ the\ ones\ we\ have\ to\ handle\ specially\n\ \ \ \ \ if\ \{\[llength\ \$args\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ #\ List\ all\ the\ entry's\ options\n\ \ \ \ \ \ \ \ \ set\ result\ \[eval\ \[list\ \$w.entry\ configure\]\ \$args\]\n\n\ \ \ \ \ \ \ \ \ #\ Remove\ entry's\ textvariable,\ we'll\ add\ our\ own\n\ \ \ \ \ \ \ \ \ set\ index\ \[lsearch\ -glob\ \$result\ \"-textvariable*\"\]\n\ \ \ \ \ \ \ \ \ set\ result\ \[lreplace\ \$result\ \$index\ \$index\]\n\n\ \ \ \ \ \ \ \ \ #\ Add\ our\ custom\ options,\ including\ textvariable\n\ \ \ \ \ \ \ \ \ foreach\ opt\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ -displayunits\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ -invalidforeground\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ -invalidbackground\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ -textvariable\n\ \ \ \ \ \ \ \ \ \ \ \ \ -units\ \n\ \ \ \ \ \ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ result\ \[Configure\ \$w\ \$opt\]\n\ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ #\ We\ added\ some\ things\ out\ of\ order\ at\ the\ end,\ so\ fix\ it\ up.\n\ \ \ \ \ \ \ \ \ lsort\ -index\ 0\ -dictionary\ \$result\n\ \ \ \ \ \}\ elseif\ \{\[llength\ \$args\]\ ==\ 1\ \}\ \{\n\ \ \ \ \ \ \ \ \ #\ Get\ the\ value\ for\ a\ single\ option\n\ \ \ \ \ \ \ \ \ set\ option\ \[lindex\ \$args\ 0\]\n\ \ \ \ \ \ \ \ \ switch\ --\ \$option\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ -units\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[list\ -units\ units\ Units\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\"\ \$options(\$option)\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ -displayunits\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[list\ -displayunits\ displayUnits\ DisplayUnits\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\"\ \$options(\$option)\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ -invalidforeground\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[list\ -invalidforeground\ invalidForeground\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ InvalidForeground\ \"\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$options(\$option)\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ -invalidbackground\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[list\ -invalidbackground\ invalidBackground\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ InvalidBackground\ \"\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$options(\$option)\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ -textvariable\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Get\ the\ name,\ defaults,\ etc.\ from\ entry\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[eval\ \[list\ \$w.entry\ configure\]\ \$args\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Put\ the\ real\ user's\ value\ in,\ not\ our\ wrapper\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ options(-textvariable)\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textVar\ \$options(-textvariable)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textVar\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lreplace\ \$result\ 4\ 4\ \$textVar\n\ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ default\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ eval\ \[list\ \$w.entry\ configure\]\ \$args\n\ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\ elseif\ \{\[llength\ \$args\]%2\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ #\ Odd\ number\ >\ 1,\ let\ the\ entry\ complain\n\ \ \ \ \ \ \ \ \ eval\ \[list\ \$w.entry\ configure\]\ \$args\n\ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ #\ Even\ number,\ set\ a\ bunch\ of\ option\ values\n\ \ \ \ \ \ \ \ \ array\ set\ opt\ \$args\n\ \ \ \ \ \ \ \ \ foreach\ option\ \[array\ names\ opt\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ switch\ --\ \$option\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -units\ -\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -displayunits\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ units\ \$opt(\$option)\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ An\ empty\ string\ means\ no\ conversion\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Normalize\ any\ non-empty\ unit\ string\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[string\ length\ \$units\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ units\ \[units::normalize\ \$units\]\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ options(\$option)\ \$units\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ unset\ opt(\$option)\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[string\ equal\ \$option\ -units\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ UpdateExternalVar\ \$w\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ UpdateInternalVar\ \$w\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -invalidforeground\ -\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -invalidbackground\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ options(\$option)\ \$opt(\$option)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ unset\ opt(\$option)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -textvariable\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ varName\ \"::\$opt(\$option)\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Remember\ what\ the\ user\ wanted.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ options(-textvariable)\ \$varName\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Put\ a\ read\ trace\ on\ the\ user's\ variable\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ to\ raise\ an\ error\ when\ reading\ a\ variable\ from\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ an\ inconsistent\ measurement.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ trace\ variable\ \$varName\ r\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[namespace\ code\ \[list\ ValidateRead\ \$w\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Put\ a\ write\ trace\ on\ the\ user's\ variable\ to\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ update\ the\ widget\ internal\ variable\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ trace\ variable\ \$varName\ w\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[namespace\ code\ \[list\ UpdateInternalVar\ \$w\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Set\ measurement\ from\ user\ var\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ \$varName\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ UpdateInternalVar\ \$w\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ We\ always\ have\ our\ own\ text\ variable\ set\ so\ just\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ unset\ this.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ unset\ opt(\$option)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ #\ foreach\n\n\ \ \ \ \ \ \ \ \ if\ \{\[array\ size\ opt\]\ !=\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ eval\ \[list\ \$w.entry\ configure\]\ \[array\ get\ opt\]\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \ \ \ #\ if\n\ \}\n\ #\ measurement::Configure\n\ #\ \n\ #-----------------------------------------------------------------------\n\ #\ measurement::UpdateExternalVar\ --\n\ #\n\ #\ \ \ \ \ Update\ the\ external\ variable\ when\ the\ user\ modifies\ the\n\ #\ \ \ \ \ measurement.\n\ #\ \n\ #\ Arguments:\n\ #\ \ \ \ \ \n\ #\ Results:\n\ #\ \ \ \ \ \n\ proc\ ::measurement::UpdateExternalVar\ \{\ w\ args\ \}\ \{\n\ \ \ \ \ upvar\ ::measurement::\$\{w\}::options\ options\n\ \ \ \ \ upvar\ ::measurement::\$\{w\}::data\ data\n\n\ \ \ \ \ if\ \{\[info\ exists\ measurement::InUpdate\]\}\ \{\n\ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \}\n\ \ \ \ \ set\ measurement::InUpdate\ 1\n\n\ \ \ \ \ set\ units\ \$options(-units)\n\ \ \ \ \ if\ \{\[info\ exists\ options(-displayunits)\]\}\ \{\n\ \ \ \ \ \ \ \ \ set\ displayunits\ \$options(-displayunits)\n\ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ set\ displayunits\ \$options(-units)\n\ \ \ \ \ \}\n\n\ \ \ \ \ set\ valueIn\ \$data(internalValue)\n\n\ \ \ \ \ if\ \{\[string\ length\ \$valueIn\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ set\ valueOut\ \$valueIn\n\ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ if\ \{\[catch\ \{units::parse\ \$valueIn\}\ meaIn\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$w.entry\ configure\ -foreground\ \$options(-invalidforeground)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$w.entry\ configure\ -background\ \$options(-invalidbackground)\n\ \ \ \ \ \ \ \ \ \ \ \ \ unset\ measurement::InUpdate\n\ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$meaIn\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ meaIn\ \$displayunits\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ if\ \{\[catch\ \{units::convert\ \$meaIn\ \$units\}\ meaOut\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$w.entry\ configure\ -foreground\ \$options(-invalidforeground)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$w.entry\ configure\ -background\ \$options(-invalidbackground)\n\ \ \ \ \ \ \ \ \ \ \ \ \ unset\ measurement::InUpdate\n\ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ set\ valueOut\ \[lindex\ \$meaOut\ 0\]\n\ \ \ \ \ \}\n\n\ \ \ \ \ \$w.entry\ configure\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ -foreground\ \$options(-validfg)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ -background\ \$options(-validbg)\n\n\ \ \ \ \ #\ Set\ the\ user's\ variable,\ if\ there\ is\ one\n\ \ \ \ \ if\ \{\[info\ exists\ options(-textvariable)\]\}\ \{\n\ \ \ \ \ \ \ \ \ set\ \$options(-textvariable)\ \$valueOut\n\ \ \ \ \ \}\n\ \ \ \ \ unset\ measurement::InUpdate\n\ \}\n\ #\ measurement::UpdateExternalVar\n\ #\ \n\ #-----------------------------------------------------------------------\n\ #\ measurement::UpdateInternalVar\ --\n\ #\n\ #\ \ \ \ \ Update\ the\ internal\ variable\ which\ is\ tied\ to\ the\ text\ the\ user\n\ #\ \ \ \ \ sees.\n\ #\ \n\ #\ Arguments:\n\ #\ \ \ \ \ \n\ #\ Results:\n\ #\ \ \ \ \ \n\ proc\ ::measurement::UpdateInternalVar\ \{\ w\ args\ \}\ \{\n\ \ \ \ \ upvar\ ::measurement::\$\{w\}::options\ options\n\ \ \ \ \ upvar\ ::measurement::\$\{w\}::data\ data\n\n\ \ \ \ \ if\ \{\[info\ exists\ measurement::InUpdate\]\}\ \{\n\ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \}\n\ \ \ \ \ set\ measurement::InUpdate\ 1\n\n\ \ \ \ \ set\ units\ \$options(-units)\n\n\ \ \ \ \ #\ Get\ the\ variable\ name\n\ \ \ \ \ set\ varName\ \$options(-textvariable)\n\n\ \ \ \ \ if\ \{\[info\ exists\ \$varName\]\}\ \{\n\ \ \ \ \ \ \ \ \ #\ Get\ the\ external\ value\n\ \ \ \ \ \ \ \ \ set\ valueIn\ \[set\ ::\$varName\]\n\ \ \ \ \ \ \ \ \ if\ \{\[string\ length\ \$valueIn\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[catch\ \{units::parse\ \$valueIn\}\ meaIn\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Restore\ the\ last,\ valid\ external\ value.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ \$varName\ \$data(externalValue)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Clear\ our\ semaphore\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ unset\ measurement::InUpdate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Raise\ an\ error.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"'\$valueIn'\ cannot\ be\ parsed\ for\ units\ conversion\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ #\ Now\ that\ it's\ valid,\ save\ it\ for\ later\n\ \ \ \ \ \ \ \ \ \ \ \ \ set\ data(externalValue)\ \$valueIn\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ #\ If\ there\ was\ no\ unit\ in\ the\ external\ variable,\ add\ one.\n\ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$meaIn\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ meaIn\ \$units\n\ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ #\ Update\ the\ measurement\n\ \ \ \ \ \ \ \ \ \ \ \ \ set\ data(internalValue)\ \[join\ \$meaIn\ \"\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ NormalizeValue\ \$w\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \ \ \ unset\ measurement::InUpdate\n\ \}\n\ #\ measurement::UpdateInternalVar\n\ #\ \n\ #-----------------------------------------------------------------------\n\ #\ measurement::NormalizeValue\ --\n\ #\n\ #\ \ \ \ \ Normalize\ the\ value\ displayed,\ include\ units,\ etc.\n\ #\ \n\ #\ Arguments:\n\ #\ \ \ \ \ \n\ #\ Results:\n\ #\ \ \ \ \ \n\ proc\ ::measurement::NormalizeValue\ \{\ w\ \}\ \{\n\ \ \ \ \ upvar\ ::measurement::\$\{w\}::options\ options\n\ \ \ \ \ upvar\ ::measurement::\$\{w\}::data\ data\n\n\ \ \ \ \ #\ Get\ the\ default\ units\ for\ this\ measurement\n\ \ \ \ \ if\ \{\[info\ exists\ options(-displayunits)\]\}\ \{\n\ \ \ \ \ \ \ \ \ set\ units\ \$options(-displayunits)\n\ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ set\ units\ \$options(-units)\n\ \ \ \ \ \}\n\n\ \ \ \ \ #\ Get\ the\ current\ value\n\ \ \ \ \ set\ valueIn\ \$data(internalValue)\n\ \ \ \ \ #\ If\ we\ can't\ parse\ the\ current\ value,\ give\ up.\n\ \ \ \ \ if\ \{\ \[catch\ \{units::parse\ \$valueIn\}\ meaIn\]\ \}\ \{\n\ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \}\n\ \ \ \ \ #\ If\ there\ aren't\ units\ in\ the\ current\ value,\ use\ the\ default\n\ \ \ \ \ if\ \{\[llength\ \$meaIn\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ lappend\ meaIn\ \$units\n\ \ \ \ \ \}\n\n\ \ \ \ \ #\ Convert\ to\ expected\ units\n\ \ \ \ \ set\ meaOut\ \[units::convert\ \$meaIn\ \$units\]\n\ \ \ \ \ set\ valueOut\ \[join\ \$meaOut\ \"\"\]\n\n\ \ \ \ \ #\ Update\ the\ display\ with\ the\ normalized\ value.\n\ \ \ \ \ set\ data(internalValue)\ \$valueOut\n\ \}\n\ #\ measurement::NormalizeValue\n\ #\ \n\ #-----------------------------------------------------------------------\n\ #\ measurement::Get\ --\n\ #\n\ #\ \ \ \ \ Get\ the\ value\ of\ the\ widget\n\ #\ \n\ #\ Arguments:\n\ #\ \ \ \ \ w\ \ \ \ -\ The\ measurement\ widget\n\ #\ \ \ \ \ what\ -\ What\ to\ return,\ \"export\"\ (the\ textvariable\ value)\ or\n\ #\ \ \ \ \ \ \ \ \ \ \ \ \"display\"\ (what\ the\ user\ typed\ and\ sees).\ \ export\ is\ the\n\ #\ \ \ \ \ \ \ \ \ \ \ \ default.\n\ #\n\ #\ Results:\n\ #\ \ \ \ \ Returns\ the\ value\ of\ the\ widget.\n\ #\n\ proc\ measurement::Get\ \{\ w\ \{what\ \"export\"\}\ \}\ \{\n\ \ \ \ \ upvar\ ::measurement::\$\{w\}::data\ data\n\ \ \ \ \ switch\ --\ \$what\ \{\n\ \ \ \ \ \ \ \ \ display\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \$data(internalValue)\n\ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ export\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ #\ Raise\ an\ error\ if\ inconsistent\n\ \ \ \ \ \ \ \ \ \ \ \ \ set\ result\ foo\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ default\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"Invalid\ option,\ '\$what'\;\ must\ be\ display\ or\ export\"\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \ \ \ return\ \$result\n\ \}\n\ #\ measurement::Get\n\ #\ \n\ #-----------------------------------------------------------------------\n\ #\ measurement::IsValid\ --\n\ #\n\ #\ \ \ \ \ Make\ sure\ that\ the\ text\ typed\ by\ the\ user\ is\ valid\ and\ that\ the\n\ #\ \ \ \ \ value\ reported\ by\ \[\$m\ get\ export\]\ and\ \[\$m\ get\ display\]\ are\n\ #\ \ \ \ \ consistent.\n\ #\ \n\ #\ Arguments:\n\ #\ \ \ \ \ w\ -\ The\ measurement\ widget.\n\ #\n\ #\ Results:\n\ #\ \ \ \ \ Returns\ 1\ if\ the\ text\ is\ valid\ and\ the\ internal\ and\ external\n\ #\ \ \ \ \ values\ are\ consistent,\ 0\ otherwise.\n\ #\n\ proc\ measurement::IsValid\ \{\ w\ \}\ \{\n\ \ \ \ \ upvar\ ::measurement::\$\{w\}::data\ data\n\n\ \ \ \ \ #\ If\ we\ can't\ parse\ the\ current\ value,\ it's\ invalid\n\ \ \ \ \ if\ \{\[catch\ \{units::parse\ \$data(internalValue)\}\]\}\ \{\n\ \ \ \ \ \ \ \ \ return\ 0\n\ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ return\ 1\n\ \ \ \ \ \}\n\ \}\n\ #\ measurement::IsValid\n\ #\ \n\ #-----------------------------------------------------------------------\n\ #\ measurement::ValidateRead\ --\n\ #\n\ #\ \ \ \ \ <short\ description>\n\ #\ \n\ #\ Arguments:\n\ #\ \ \ \ \ \n\ #\ Results:\n\ #\ \ \ \ \ \n\ proc\ measurement::ValidateRead\ \{\ w\ args\ \}\ \{\n\ \ \ \ \ upvar\ ::measurement::\$\{w\}::data\ data\n\ \ \ \ \ if\ \{\ !\ \[IsValid\ \$w\]\ \}\ \{\n\ \ \ \ \ \ \ \ \ error\ \"'\$data(internalValue)'\ cannot\ be\ parsed\ for\ units\ conversion\"\n\ \ \ \ \ \}\n\ \}\n\ #\ measurement::ValidateRead\n\ #\ \n\ #-----------------------------------------------------------------------\n\ #\ measurement::Test\ --\n\ #\n\ #\ \ \ \ \ <short\ description>\n\ #\ \n\ #\ Arguments:\n\ #\ \ \ \ \ \n\ #\ Results:\n\ #\ \ \ \ \ \n\ proc\ ::measurement::Test\ \{\ \{w\ \"\"\}\ \}\ \{\n\ \ \ \ \ #\ Just\ in\ case.\n\ \ \ \ \ destroy\ \$w.test\n\n\ \ \ \ \ set\ f\ \[frame\ \$w.test\]\n\ \ \ \ \ pack\ \$f\n\n\ \ \ \ \ set\ ::edit\ cm\n\ \ \ \ \ set\ ::show\ cm\n\n\ \ \ \ \ frame\ \$f.top\n\ \ \ \ \ pack\ \$f.top\ -side\ top\ -expand\ 1\ -fill\ both\ -padx\ 2m\ -pady\ 2m\n\ \ \ \ \ label\ \$f.top.label\ -text\ \"Input:\"\n\ \ \ \ \ pack\ \$f.top.label\ -side\ left\ \n\ \ \ \ \ measurement\ \$f.top.entry\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ -units\ \$::edit\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ -displayunits\ \$::show\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ -textvariable\ foo\n\ \ \ \ \ \$f.top.entry\ configure\ -invalidforeground\ red\n\ \ \ \ \ pack\ \$f.top.entry\ -side\ left\ -expand\ 1\ -fill\ x\n\n\ \ \ \ \ frame\ \$f.edit\n\ \ \ \ \ pack\ \$f.edit\ -side\ top\ -expand\ 1\ -fill\ both\ -padx\ 2m\ -pady\ 2m\n\ \ \ \ \ label\ \$f.edit.label\ -text\ \"Edit\ in:\"\ -width\ 10\n\ \ \ \ \ pack\ \$f.edit.label\ -side\ left\n\ \ \ \ \ foreach\ unit\ \{pt\ cm\ in\ ft\}\ \{\n\ \ \ \ \ \ \ \ \ radiobutton\ \$f.edit.\$unit\ -text\ \$unit\ -width\ 3\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -command\ \[list\ \$f.top.entry\ configure\ -displayunits\ \$unit\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -variable\ edit\ -value\ \$unit\n\ \ \ \ \ \ \ \ \ pack\ \$f.edit.\$unit\ -side\ left\n\ \ \ \ \ \}\n\n\ \ \ \ \ frame\ \$f.show\n\ \ \ \ \ pack\ \$f.show\ -side\ top\ -expand\ 1\ -fill\ both\ -padx\ 2m\ -pady\ 2m\n\ \ \ \ \ label\ \$f.show.label\ -text\ \"Export\ in:\"\ -width\ 10\n\ \ \ \ \ pack\ \$f.show.label\ -side\ left\n\ \ \ \ \ foreach\ unit\ \{pt\ cm\ in\ ft\}\ \{\n\ \ \ \ \ \ \ \ \ radiobutton\ \$f.show.\$unit\ -text\ \$unit\ -width\ 3\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -command\ \[list\ \$f.top.entry\ configure\ -units\ \$unit\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -variable\ show\ -value\ \$unit\n\ \ \ \ \ \ \ \ \ pack\ \$f.show.\$unit\ -side\ left\n\ \ \ \ \ \}\n\n\ \ \ \ \ frame\ \$f.btm\n\ \ \ \ \ pack\ \$f.btm\ -side\ top\ -expand\ 1\ -fill\ both\ -padx\ 2m\ -pady\ 2m\n\ \ \ \ \ label\ \$f.btm.label\ -textvariable\ show\n\ \ \ \ \ pack\ \$f.btm.label\ -side\ left\ \n\ \ \ \ \ entry\ \$f.btm.entry\ -textvariable\ foo\n\ \ \ \ \ pack\ \$f.btm.entry\ -side\ left\ -expand\ 1\ -fill\ x\n\ \}\n\ #\ measurement::Test\n\ #\ \n\n\ #\ Make\ it\ easier\ to\ create\ measurement\ widgets\n\ namespace\ import\ measurement::measurement\n\n======\n\n\[ARR\]:\ Hi,\ I\ like\ to\ test\ this\ out.\ Where\ can\ I\ find\ the\ units.tcl\ file?\ I\ tried\ 'package\ req\ units'\ in\ my\ ActiveTcl\ 8.5\ but\ the\ proc\ 'units::normalize'\ is\ not\ there.\n\n======\n\n<<categories>>\ GUI} CALL {my revision {Measurement widget with units conversion}} CALL {::oo::Obj71204 process revision/Measurement+widget+with+units+conversion} CALL {::oo::Obj71202 process}

-errorcode

NONE

-errorinfo

Unknow state transition: LINE -> END
    while executing
"error $msg"
    (class "::Wiki" method "render_wikit" line 6)
    invoked from within
"my render_$default_markup $N $C $mkup_rendering_engine"
    (class "::Wiki" method "render" line 8)
    invoked from within
"my render $name $C"
    (class "::Wiki" method "revision" line 31)
    invoked from within
"my revision $page"
    (class "::Wiki" method "process" line 56)
    invoked from within
"$server process [string trim $uri /]"

-errorline

4