1
2#----- conversions to SI units
3
4# mass -> kg
5
6proc convert_mass {val unit {dir from}} {
7  switch -- $unit {
8    kg      {set scl 1.0}
9    lbm     {set scl 0.45359237}
10    slug    {set scl 14.593881}
11    g       {set scl 0.001}
12    oz      {set scl 0.028349523}
13    ton     {set scl 907.18474}
14    default {return -code error "unknown mass conversion - $unit"}
15  }
16  regsub -all / $val {*1.0/} exp
17  if {$dir == "from"} {
18    return [expr ($exp) * $scl]
19  }
20  return [expr ($exp) / $scl]
21}
22
23# length -> m
24
25proc convert_length {val unit {dir from}} {
26  switch -- $unit {
27    m       {set scl 1.0}
28    ft      {set scl 0.3048}
29    cm      {set scl 0.01}
30    mm      {set scl 0.001}
31    in      {set scl 0.0254}
32    yd      {set scl 0.9144}
33    km      {set scl 1000.0}
34    mi      {set scl 1609.344}
35    micron  {set scl 1.0e-06}
36    thou    -
37    mil     {set scl 2.54e-05}
38    default {return -code error "unknown length conversion - $unit"}
39  }
40  regsub -all / $val {*1.0/} exp
41  if {$dir == "from"} {
42    return [expr ($exp) * $scl]
43  }
44  return [expr ($exp) / $scl]
45}
46
47# time -> s
48
49proc convert_time {val unit {dir from}} {
50  switch -- $unit {
51    sec     -
52    s       {set scl 1.0}
53    min     {set scl 60.0}
54    hr      {set scl 3600.0}
55    default {return -code error "unknown time conversion - $unit"}
56  }
57  regsub -all / $val {*1.0/} exp
58  if {$dir == "from"} {
59    return [expr ($exp) * $scl]
60  }
61  return [expr ($exp) / $scl]
62}
63
64# temperature -> K
65
66proc convert_temperature {val unit {dir from}} {
67  regsub -all / $val {*1.0/} exp
68  if {$dir == "from"} {
69    switch -- $unit {
70      K {return [expr $exp]}
71      C {return [expr ($exp) + 273.16]}
72      R {return [expr ($exp) / 1.8]}
73      F {return [expr (($exp) - 32.0) / 1.8 + 273.16]}
74    }
75  } else {
76    switch -- $unit {
77      K {return [expr $exp]}
78      C {return [expr ($exp) - 273.16]}
79      R {return [expr ($exp) * 1.8]}
80      F {return [expr (($exp) - 273.16) * 1.8 + 32.0]}
81    }
82  }
83  return -code error "unknown temperature conversion - $unit"
84}
85
86# angle -> rad
87
88proc convert_angle {val unit {dir from}} {
89  switch -- $unit {
90    rad     {set scl 1.0}
91    deg     {set scl 0.017453293}
92    rev     {set scl 6.2831853}
93    grad    {set scl 0.01570796}
94    default {return -code error "unknown angle conversion - $unit"}
95  }
96  regsub -all / $val {*1.0/} exp
97  if {$dir == "from"} {
98    return [expr ($exp) * $scl]
99  }
100  return [expr ($exp) / $scl]
101}
102
103# area -> m^2
104
105proc convert_area {val unit {dir from}} {
106  switch -- $unit {
107    m^2     {set scl 1.0}
108    ft^2    {set scl 0.09290304}
109    cm^2    {set scl 1.0e-04}
110    mm^2    {set scl 1.0e-06}
111    in^2    {set scl 6.4516e-04}
112    yd^2    {set scl 0.83612736}
113    default {return -code error "unknown area conversion - $unit"}
114  }
115  regsub -all / $val {*1.0/} exp
116  if {$dir == "from"} {
117    return [expr ($exp) * $scl]
118  }
119  return [expr ($exp) / $scl]
120}
121
122# volume -> m^3
123
124proc convert_volume {val unit {dir from}} {
125  switch -- $unit {
126    m^3     {set scl 1.0}
127    ft^3    {set scl 0.028316847}
128    cc      -
129    ml      -
130    cm^3    {set scl 1.0e-06}
131    mm^3    {set scl 1.0e-09}
132    in^3    {set scl 1.6387064e-05}
133    yd^3    {set scl 0.76455486}
134    liter   -
135    l       {set scl 0.001}
136    gal     {set scl 0.003785412}
137    cup     {set scl 2.3658825e-04}
138    qt      {set scl 9.46353e-04}
139    default {return -code error "unknown volume conversion - $unit"}
140  }
141  regsub -all / $val {*1.0/} exp
142  if {$dir == "from"} {
143    return [expr ($exp) * $scl]
144  }
145  return [expr ($exp) / $scl]
146}
147
148# velocity -> m/s
149
150proc convert_velocity {val unit {dir from}} {
151  switch -- $unit {
152    m/s     {set scl 1.0}
153    ft/s    {set scl 0.3048}
154    cm/s    {set scl 0.01}
155    mm/s    {set scl 0.001}
156    in/s    {set scl 0.0254}
157    km/h    {set scl 0.27777778}
158    mi/h    {set scl 0.44704}
159    mach    {set scl 340.29}
160    default {return -code error "unknown velocity conversion - $unit"}
161  }
162  regsub -all / $val {*1.0/} exp
163  if {$dir == "from"} {
164    return [expr ($exp) * $scl]
165  }
166  return [expr ($exp) / $scl]
167}
168
169# rotation rate -> rad/s
170
171proc convert_rotation {val unit {dir from}} {
172  switch -- $unit {
173    rad/s   {set scl 1.0}
174    deg/s   {set scl 0.017453293}
175    rev/s   {set scl 6.2831853}
176    rad/min {set scl 0.016666667}
177    deg/min {set scl 2.9088821e-04}
178    rev/min -
179    RPM     {set scl 0.10471976}
180    default {return -code error "unknown rotation rate conversion - $unit"}
181  }
182  regsub -all / $val {*1.0/} exp
183  if {$dir == "from"} {
184    return [expr ($exp) * $scl]
185  }
186  return [expr ($exp) / $scl]
187}
188
189# density -> kg/m^3
190
191proc convert_density {val unit {dir from}} {
192  switch -- $unit {
193    kg/m^3    {set scl 1.0}
194    lbm/ft^3  {set scl 16.018463}
195    slug/ft^3 {set scl 515.37804}
196    g/cm^3    {set scl 1000.0}
197    default   {return -code error "unknown density conversion - $unit"}
198  }
199  regsub -all / $val {*1.0/} exp
200  if {$dir == "from"} {
201    return [expr ($exp) * $scl]
202  }
203  return [expr ($exp) / $scl]
204}
205
206# pressure -> N/m^2 (Pa)
207
208proc convert_pressure {val unit {dir from}} {
209  switch -- $unit {
210    N/m^2    -
211    Pa       {set scl 1.0}
212    MPa      {set scl 1.0e+06}
213    lbf/in^2 -
214    psi      {set scl 6894.7572}
215    lbf/ft^2 -
216    psf      {set scl 47.880258}
217    bar      {set scl 1.0e+05}
218    atm      {set scl 101325.0}
219    dyn/cm^2 {set scl 0.1}
220    inHg     {set scl 3386.388}
221    mmHg     -
222    torr     {set scl 133.3224}
223    default  {return -code error "unknown pressure conversion - $unit"}
224  }
225  regsub -all / $val {*1.0/} exp
226  if {$dir == "from"} {
227    return [expr ($exp) * $scl]
228  }
229  return [expr ($exp) / $scl]
230}
231
232# enthalpy -> J/kg
233
234proc convert_enthalpy {val unit {dir from}} {
235  switch -- $unit {
236    J/kg        {set scl 1.0}
237    kJ/kg       {set scl 1000.0}
238    BTU/lbm     {set scl 2325.9723}
239    BTU/slug    {set scl 72.293539}
240    ft-lbf/lbm  {set scl 2.9890669}
241    ft-lbf/slug {set scl 0.09290318}
242    default     {return -code error "unknown enthalpy conversion - $unit"}
243  }
244  regsub -all / $val {*1.0/} exp
245  if {$dir == "from"} {
246    return [expr ($exp) * $scl]
247  }
248  return [expr ($exp) / $scl]
249}
250
251# force -> N
252
253proc convert_force {val unit {dir from}} {
254  switch -- $unit {
255    N       {set scl 1.0}
256    lbf     {set scl 4.4482216}
257    pdl     {set scl 0.13825516}
258    dyn     {set scl 1.0e-05}
259    default {return -code error "unknown force conversion - $unit"}
260  }
261  regsub -all / $val {*1.0/} exp
262  if {$dir == "from"} {
263    return [expr ($exp) * $scl]
264  }
265  return [expr ($exp) / $scl]
266}
267
268# energy/work/torque -> J
269
270proc convert_energy {val unit {dir from}} {
271  switch -- $unit {
272    N-m     -
273    m-N     -
274    J       {set scl 1.0}
275    kJ      {set scl 1000.0}
276    ft-lbf  {set scl 1.3558179}
277    ft-pdl  {set scl 0.042140172}
278    BTU     {set scl 1055.0433}
279    cal     {set scl 4.184}
280    kcal    {set scl 4184.0}
281    erg     {set scl 1.0e-07}
282    default {return -code error "unknown energy conversion - $unit"}
283  }
284  regsub -all / $val {*1.0/} exp
285  if {$dir == "from"} {
286    return [expr ($exp) * $scl]
287  }
288  return [expr ($exp) / $scl]
289}
290
291proc convert_work {val unit {dir from}} {
292  return [convert_energy $val $unit $dir]
293}
294
295proc convert_torque {val unit {dir from}} {
296  return [convert_energy $val $unit $dir]
297}
298
299# power -> W
300
301proc convert_power {val unit {dir from}} {
302  switch -- $unit {
303    J/s      -
304    W        {set scl 1.0}
305    kW       {set scl 1000.0}
306    ft-lbf/s {set scl 1.3558179}
307    ft-pdl/s {set scl 0.042140172}
308    BTU/s    {set scl 1055.0433}
309    BTU/hr   {set scl 0.29306758}
310    hp       {set scl 745.69987}
311    default  {return -code error "unknown power conversion - $unit"}
312  }
313  regsub -all / $val {*1.0/} exp
314  if {$dir == "from"} {
315    return [expr ($exp) * $scl]
316  }
317  return [expr ($exp) / $scl]
318}
319
320# mass flow rate -> kg/s
321
322proc convert_massflow {val unit {dir from}} {
323  switch -- $unit {
324    kg/s    {set scl 1.0}
325    lbm/s   {set scl 0.45359237}
326    slug/s  {set scl 14.593881}
327    g/s     {set scl 0.001}
328    kg/h    {set scl 2.7777778e-04}
329    lbm/h   {set scl 1.2599788e-04}
330    slug/h  {set scl 0.0040538558}
331    default {return -code error "unknown mass flow rate conversion - $unit"}
332  }
333  regsub -all / $val {*1.0/} exp
334  if {$dir == "from"} {
335    return [expr ($exp) * $scl]
336  }
337  return [expr ($exp) / $scl]
338}
339
340# volume flow -> m^3/s
341
342proc convert_volflow {val unit {dir from}} {
343  switch -- $unit {
344    m^3/s    {set scl 1.0}
345    ft^3/s   {set scl 0.028316847}
346    gal/s    {set scl 0.003785412}
347    l/s      {set scl 0.001}
348    ml/s     -
349    cc/s     -
350    cm^3/s   {set scl 1.0e-06}
351    m^3/min  {set scl 0.016666667}
352    ft^3/min {set scl 4.7194744e-04}
353    gal/min  -
354    gpm      {set scl 6.30902e-05}
355    default  {return -code error "unknown volume flow conversion - $unit"}
356  }
357  regsub -all / $val {*1.0/} exp
358  if {$dir == "from"} {
359    return [expr ($exp) * $scl]
360  }
361  return [expr ($exp) / $scl]
362}
363
364# dynamic viscosity -> N-s/m^2
365
366proc convert_dynvisc {val unit {dir from}} {
367  switch -- $unit {
368    kg/m-s     -
369    N-s/m^2    {set scl 1.0}
370    slug/ft-s  -
371    lbf-s/ft^2 {set scl 47.880187}
372    lbm/ft-s   {set scl 1.4881639}
373    dyn-s/cm^2 -
374    g/cm-s     -
375    Poise      {set scl 0.1}
376    default    {
377      return -code error "unknown dynamic viscosity conversion - $unit"
378    }
379  }
380  regsub -all / $val {*1.0/} exp
381  if {$dir == "from"} {
382    return [expr ($exp) * $scl]
383  }
384  return [expr ($exp) / $scl]
385}
386
387# kinematic viscosity -> m^2/s
388
389proc convert_kinvisc {val unit {dir from}} {
390  switch -- $unit {
391    Stoke   -
392    m^2/s   {set scl 1.0}
393    ft^2/s  {set scl 0.09290304}
394    default {
395      return -code error "unknown kinematic viscosity conversion - $unit"
396    }
397  }
398  regsub -all / $val {*1.0/} exp
399  if {$dir == "from"} {
400    return [expr ($exp) * $scl]
401  }
402  return [expr ($exp) / $scl]
403}
404
405# specific heat -> J/kg-K
406
407proc convert_spheat {val unit {dir from}} {
408  switch -- $unit {
409    J/kg-K        {set scl 1.0}
410    kJ/kg-K       {set scl 1000.0}
411    erg/g-K       {set scl 0.0001}
412    ft-lbf/lbm-R  {set scl 5.3803205}
413    ft-lbf/slug-R {set scl 0.16722572}
414    BTU/lbm-R     {set scl 4186.7502}
415    BTU/slug-R    {set scl 130.12837}
416    default       {
417      return -code error "unknown specific heat conversion - $unit"
418    }
419  }
420  regsub -all / $val {*1.0/} exp
421  if {$dir == "from"} {
422    return [expr ($exp) * $scl]
423  }
424  return [expr ($exp) / $scl]
425}
426
427# conductivity -> N/(s*K)
428
429proc convert_conduct {val unit {dir from}} {
430  switch -- $unit {
431    J/m-s-K    -
432    N/s-K      {set scl 1.0}
433    lbf/s-R    {set scl 8.0067989}
434    BTU/ft-s-R {set scl 6230.5706}
435    cal/m-s-K  {set scl 4.184}
436    dyn/s-K    {set scl 1.0e-05}
437    default    {return -code error "unknown conductivity conversion - $unit"}
438  }
439  regsub -all / $val {*1.0/} exp
440  if {$dir == "from"} {
441    return [expr ($exp) * $scl]
442  }
443  return [expr ($exp) / $scl]
444}
445
446# SI units
447
448proc unitsSI {type} {
449  switch -- $type {
450    mass        {return [list kg 1.0]}
451    length      {return [list m 1.0]}
452    time        {return [list s 1.0]}
453    temperature {return [list K 1.0]}
454    angle       {return [list deg 57.2958]}
455    area        {return [list m^2 1.0]}
456    volume      {return [list m^3 1.0]}
457    velocity    {return [list m/s 1.0]}
458    rotation    {return [list RPM 9.54930]}
459    density     {return [list kg/m^3 1.0]}
460    pressure    {return [list MPa 1.0e-06]}
461    enthalpy    {return [list kJ/kg 0.001]}
462    force       {return [list N 1.0]}
463    energy      {return [list J 1.0]}
464    work        {return [list J 1.0]}
465    power       {return [list W 1.0]}
466    torque      {return [list m-N 1.0]}
467    massflow    {return [list kg/s 1.0]}
468    volflow     {return [list m^3/s 1.0]}
469    dynvisc     {return [list N-s/m^2 1.0]}
470    kinvisc     {return [list m^2/s 1.0]}
471    spheat      {return [list kJ/kg-K 0.001]}
472    conduct     {return [list N/s-K 1.0]}
473  }
474  return [list $type 1.0]
475}
476
477# SI -> EE units
478
479proc unitsEE {type} {
480  switch -- $type {
481    mass        {return [list lbm 2.20462]}
482    length      {return [list ft 3.28084]}
483    time        {return [list s 1.0]}
484    temperature {return [list R 1.8]}
485    angle       {return [list deg 57.2958]}
486    area        {return [list ft^2 10.7639]}
487    volume      {return [list ft^3 35.3147]}
488    velocity    {return [list ft/s 3.28084]}
489    rotation    {return [list RPM 9.54930]}
490    density     {return [list lbm/ft^3 0.062428]}
491    pressure    {return [list psi 0.000145038]}
492    enthalpy    {return [list BTU/lbm 0.000429928]}
493    force       {return [list lbf 0.224809]}
494    energy      {return [list BTU 0.000947828]}
495    work        {return [list ft-lbf 0.737562]}
496    power       {return [list hp 0.00134102]}
497    torque      {return [list ft-lbf 0.737562]}
498    massflow    {return [list lbm/s 2.20462]}
499    volflow     {return [list ft^3/s 35.3147]}
500    dynvisc     {return [list lbf-s/ft^2 0.0208855]}
501    kinvisc     {return [list ft^2/s 10.7639]}
502    spheat      {return [list BTU/lbm-R 0.000238849]}
503    conduct     {return [list lbf/s-R 0.124894]}
504  }
505  return [list $type 1.0]
506}
507
508# SI -> EG units
509
510proc unitsEG {type} {
511  switch -- $type {
512    mass        {return [list slug 0.0685219]}
513    length      {return [list ft 3.28084]}
514    time        {return [list s 1.0]}
515    temperature {return [list R 1.8]}
516    angle       {return [list deg 57.2958]}
517    area        {return [list ft^2 10.7639]}
518    volume      {return [list ft^3 35.3147]}
519    velocity    {return [list ft/s 3.28084]}
520    rotation    {return [list RPM 9.54930]}
521    density     {return [list slug/ft^3 0.00194032]}
522    pressure    {return [list lbf/ft^2 0.0208854]}
523    enthalpy    {return [list ft-lbf/slug 10.7639]}
524    force       {return [list lbf 0.224809]}
525    energy      {return [list ft-lbf 0.737562]}
526    work        {return [list ft-lbf 0.737562]}
527    power       {return [list ft-lbf/s 0.737562]}
528    torque      {return [list ft-lbf 0.737562]}
529    massflow    {return [list slug/s 0.0685219]}
530    volflow     {return [list ft^3/s 35.3147]}
531    dynvisc     {return [list lbf-s/ft^2 0.0208855]}
532    kinvisc     {return [list ft^2/s 10.7639]}
533    spheat      {return [list ft-lbf/slug-R 5.97994]}
534    conduct     {return [list lbf/s-R 0.124894]}
535  }
536  return [list $type 1.0]
537}
538
539#---------- unit conversion panel ----------
540
541set _UnitTypes {mass length time temperature angle area volume \
542  velocity rotation density pressure enthalpy force energy \
543  power massflow volflow dynvisc kinvisc spheat conduct}
544
545array set _UnitList {
546  mass        {kg lbm slug g oz ton}
547  length      {m ft cm mm in yd km mi micron mil}
548  time        {s min hr}
549  temperature {K R C F}
550  angle       {rad deg rev grad}
551  area        {m^2 ft^2 cm^2 mm^2 in^2 yd^2}
552  volume      {m^3 ft^3 cm^3 mm^3 in^3 yd^3 gal l ml cup qt}
553  velocity    {m/s ft/s cm/s mm/s in/s km/h mi/h mach}
554  rotation    {rad/s RPM deg/s rev/s rad/min deg/min}
555  density     {kg/m^3 lbm/ft^3 slug/ft^3 g/cm^3}
556  pressure    {Pa MPa psi psf bar atm lbf/in^2 lbf/ft^2 dyn/cm^2 \
557               inHg mmHg torr}
558  enthalpy    {J/kg kJ/kg BTU/lbm BTU/slug ft-lbf/lbm ft-lbf/slug}
559  force       {N lbf pdl dyn}
560  energy      {J kJ ft-lbf ft-pdl BTU m-N cal kcal erg}
561  power       {W kW J/s ft-lbf/s ft-pdl/s BTU/s BTU/hr hp}
562  massflow    {kg/s lbm/s slug/s g/s kg/h lbm/h slug/h}
563  volflow     {m^3/s ft^3/s cm^3/s gal/s gpm l/s m^3/min ft^3/min}
564  dynvisc     {N-s/m^2 lbf-s/ft^2 kg/m-s lbm/ft-s slug/ft-s Poise \
565               dyn-s/cm^2 g/cm-s}
566  kinvisc     {m^2/s ft^2/s Stoke}
567  spheat      {J/kg-K kJ/kg-K ft-lbf/lbm-R ft-lbf/slug-R \
568               BTU/lbm-R BTU/slug-R erg/g-K}
569  conduct     {N/s-K lbf/s-R BTU/ft-s-R J/m-s-K cal/m-s-K dyn/s-K}
570}
571
572array set _UnitData {
573  mass:label        Mass
574  length:label      Length
575  time:label        Time
576  temperature:label Temperature
577  angle:label       Angle
578  area:label        Area
579  volume:label      Volume
580  velocity:label    Velocity
581  rotation:label    Rotation
582  density:label     Density
583  pressure:label    Pressure
584  enthalpy:label    Enthalpy
585  force:label       Force
586  energy:label      Energy/Work/Torque
587  power:label       Power
588  massflow:label    "Mass Flow Rate"
589  volflow:label     "Volume Flow Rate"
590  dynvisc:label     "Dynamic Viscosity"
591  kinvisc:label     "Kinematic Viscosity"
592  spheat:label      "Specific Heat"
593  conduct:label     Conductivity
594  mass:last         {0 1}
595  length:last       {0 1}
596  time:last         {0 0}
597  temperature:last  {0 1}
598  angle:last        {0 1}
599  area:last         {0 1}
600  volume:last       {0 1}
601  velocity:last     {0 1}
602  rotation:last     {0 1}
603  density:last      {0 1}
604  pressure:last     {0 2}
605  enthalpy:last     {0 2}
606  force:last        {0 1}
607  energy:last       {0 2}
608  power:last        {0 3}
609  massflow:last     {0 1}
610  volflow:last      {0 1}
611  dynvisc:last      {0 1}
612  kinvisc:last      {0 1}
613  spheat:last       {0 2}
614  conduct:last      {0 1}
615  type              mass
616  input:value       1
617  input:unit        kg
618  output:value      1
619  output:unit       kg
620  saved             ""
621  regkey            "UnitConversions"
622}
623
624proc units_convert {{loc .}} {
625  global _UnitData _UnitTypes
626  set w .unit_conversions
627  if {[winfo exists $w]} {
628    wm deiconify $w
629    raise $w
630    focus $w.values.input.ent
631    $w.values.input.ent selection range 0 end
632    return
633  }
634  toplevel $w
635  units:create $w
636  catch {center_window $w $loc}
637}
638
639proc units_read {{key ""}} {
640  global _UnitTypes _UnitData
641  if {[info procs tclreg_get] == ""} {return}
642  if {$key == ""} {
643    set key $_UnitData(regkey)
644  }
645  foreach i $_UnitTypes {
646    if {![catch {tclreg_get $key $i} last] &&
647      [llength $last] == 2} {
648      set _UnitData($i:last) $last
649    }
650  }
651  foreach i {type saved} {
652    if {![catch {tclreg_get $key $i} val] && $val != ""} {
653      set _UnitData($i) $val
654    }
655  }
656  foreach i {input output} {
657    if {![catch {tclreg_get $key $i} data] &&
658      [llength $data] == 2} {
659      set _UnitData($i:value) [lindex $data 0]
660      set _UnitData($i,unit) [lindex $data 1]
661    }
662  }
663}
664
665proc units_write {{key ""}} {
666  global _UnitTypes _UnitData
667  if {[info procs tclreg_set] == ""} {return}
668  if {$key == ""} {
669    set key $_UnitData(regkey)
670  }
671  foreach i $_UnitTypes {
672    catch {tclreg_set $key $i $_UnitData($i:last)}
673  }
674  foreach i {type saved} {
675    catch {tclreg_set $key $i $_UnitData($i)}
676  }
677  foreach i {input output} {
678    catch {tclreg_set $key $i "$_UnitData($i:value) $_UnitData($i:unit)"}
679  }
680}
681
682proc units:create {top} {
683  global _UnitData _UnitTypes
684
685  wm title $top "Unit Conversions"
686  wm protocol $top WM_DELETE_WINDOW "units:destroy $top"
687  wm resizable $top 0 0
688
689  if {$top == "."} {
690    set w ""
691  } else {
692    set w $top
693  }
694
695  set f [frame $w.type]
696  pack $f -side top -anchor w -padx 5 -pady 5
697
698  label $f.lab -text "Unit Type"
699  pack $f.lab -side left
700  menubutton $f.but -indicatoron 1 -width 20 -menu $f.but.menu \
701    -relief raised -text Mass -padx 3 -pady 3 \
702    -highlightthickness 1 -takefocus 1
703  pack $f.but -side left -padx 5
704
705  menu $f.but.menu -tearoff 0
706  foreach i $_UnitTypes {
707    $f.but.menu add command -label $_UnitData($i:label) \
708      -command "units:change {$w} $i"
709  }
710
711  frame $w.units
712  pack $w.units -side top -fill x -expand 1
713
714  set f [frame $w.units.input]
715  pack $f -side left -padx 5 -fill x -expand 1
716
717  label $f.lab -text "From Units Of"
718  pack $f.lab -side top -anchor w
719  scrollbar $f.scroll -command "$f.list yview"
720  pack $f.scroll -side right -fill y
721  listbox $f.list -width 15 -height 5 -yscroll "$f.scroll set" \
722    -selectmode browse -exportselection 0
723  pack $f.list -side left -fill both -expand 1
724
725  bind $f.list <<ListboxSelect>> "units:compute {$w}"
726
727  set f [frame $w.units.output]
728  pack $f -side right -padx 5 -fill x -expand 1
729
730  label $f.lab -text "To Units Of"
731  pack $f.lab -side top -anchor w
732  scrollbar $f.scroll -command "$f.list yview"
733  pack $f.scroll -side right -fill y
734  listbox $f.list -width 15 -height 5 -yscroll "$f.scroll set" \
735    -selectmode browse -exportselection 0
736  pack $f.list -side top -fill both -expand 1
737
738  bind $f.list <<ListboxSelect>> "units:compute {$w}"
739
740  frame $w.values
741  pack $w.values -side top -padx 5 -pady 5 -fill x -expand 1
742
743  set f [frame $w.values.input]
744  pack $f -side top -fill x -expand 1
745  label $f.lab -text Input -width 6 -anchor w
746  pack $f.lab -side left
747  entry $f.ent -width 20 -textvariable _UnitData(input:value)
748  pack $f.ent -side left -fill x -expand 1
749  label $f.unit -width 9 -textvariable _UnitData(input:unit) -anchor w
750  pack $f.unit -side left
751
752  set f [frame $w.values.output]
753  pack $f -side top -fill x -expand 1
754  label $f.lab -text Output -width 6 -anchor w
755  pack $f.lab -side left
756  entry $f.ent -width 20 -textvariable _UnitData(output:value) \
757    -state disabled -bg [$f.lab cget -bg]
758  pack $f.ent -side left -fill x -expand 1
759  label $f.unit -width 9 -textvariable _UnitData(output:unit) -anchor w
760  pack $f.unit -side left
761
762  set f [frame $w.but]
763  pack $f -side top -padx 5 -pady 5 -fill x -expand 1
764
765  button $f.sto -text STO -width 5 -highlightthickness 1 -pady 0 \
766    -underline 0 -command "units:store {$w}"
767  button $f.rcl -text RCL -width 5 -highlightthickness 1 -pady 0 \
768    -underline 0 -command "units:recall {$w}"
769  button $f.copy -text Copy -width 5 -highlightthickness 1 -pady 0 \
770    -underline 0 -command "units:copy {$w}"
771  button $f.help -text Help -width 5 -highlightthickness 1 -pady 0 \
772    -underline 0 -command units_help
773  if {$top == "."} {
774    button $f.exit -text Exit -width 5 -highlightthickness 1 -pady 0 \
775      -underline 0 -command "units:destroy $top"
776  } else {
777    button $f.exit -text Close -width 5 -highlightthickness 1 -pady 0 \
778      -underline 4 -command "units:destroy $top"
779  }
780  pack $f.sto $f.rcl $f.copy $f.help $f.exit -side left -expand 1
781
782  if {$_UnitData(saved) == ""} {$f.rcl configure -state disabled}
783  if {[info procs units_help] == ""} {$f.help configure -state disabled}
784
785  bind $top <Alt-s> "units:invoke $f.sto"
786  bind $top <Alt-r> "units:invoke $f.rcl"
787  bind $top <Alt-c> "units:invoke $f.copy"
788  bind $top <Alt-h> "units:invoke $f.help"
789  bind $top <Alt-e> "units:invoke $f.exit"
790
791  units:set $w
792
793  focus $w.values.input.ent
794  $w.values.input.ent selection range 0 end
795
796  trace variable _UnitData(input:value) w "units:update {$w}"
797}
798
799proc units:invoke {but} {
800  if {[$but cget -state] == "normal"} {
801    $but configure -relief sunken
802    update idletasks
803    after 250
804    $but configure -relief raised
805    $but invoke
806  }
807}
808
809proc units:destroy {top} {
810  if {$top == "."} {
811    set w ""
812  } else {
813    set w $top
814  }
815  trace vdelete _UnitData(input:value) w "units:update {$w}"
816  units:last $w
817  destroy $top
818}
819
820proc units:last {w} {
821  global _UnitData
822  set input [$w.units.input.list curselection]
823  set output [$w.units.output.list curselection]
824  set _UnitData($_UnitData(type):last) [list $input $output]
825}
826
827proc units:set {w} {
828  global _UnitData _UnitList
829  set unit $_UnitData(type)
830  $w.type.but configure -text $_UnitData($unit:label)
831  set n 0
832  foreach i {input output} {
833    $w.units.$i.list delete 0 end
834    foreach j $_UnitList($unit) {
835      $w.units.$i.list insert end $j
836    }
837    set sel [lindex $_UnitData($unit:last) $n]
838    if {$sel != ""} {
839      $w.units.$i.list selection set $sel $sel
840      $w.units.$i.list see $sel
841    }
842    incr n
843  }
844  units:compute $w
845}
846
847proc units:change {w unit} {
848  global _UnitData
849  units:last $w
850  set _UnitData(type) $unit
851  units:set $w
852}
853
854proc units:update {w name1 name2 op} {
855  units:compute $w
856}
857
858proc units:compute {w} {
859  global _UnitData
860  foreach i {input output} {
861    set sel [$w.units.$i.list curselection]
862    if {$sel == {}} {
863      set _UnitData($i:unit) ""
864    } else {
865      set _UnitData($i:unit) [$w.units.$i.list get $sel $sel]
866    }
867  }
868  set conv convert_$_UnitData(type)
869  if {[info commands $conv] == "" ||
870    $_UnitData(input:unit) == "" ||
871    $_UnitData(output:unit) == ""} {
872    set _UnitData(output:value) ""
873  } elseif {$_UnitData(input:unit) == $_UnitData(output:unit)} {
874    regsub -all / $_UnitData(input:value) {*1.0/} exp
875    if {[catch {expr double($exp)} output]} {
876      set _UnitData(output:value) ""
877    } else {
878      set _UnitData(output:value) [format "%g" $output]
879    }
880  } else {
881    if {[catch {$conv $_UnitData(input:value) $_UnitData(input:unit)} val] ||
882      [catch {$conv $val $_UnitData(output:unit) to} output]} {
883      set _UnitData(output:value) ""
884    } else {
885      set _UnitData(output:value) [format "%g" $output]
886    }
887  }
888  if {$_UnitData(output:value) == ""} {
889    $w.but.sto configure -state disabled
890    $w.but.copy configure -state disabled
891  } else {
892    $w.but.sto configure -state normal
893    $w.but.copy configure -state normal
894  }
895}
896
897proc units:store {w} {
898  global _UnitData
899  set _UnitData(saved) $_UnitData(output:value)
900  $w.but.rcl configure -state normal
901}
902
903proc units:recall {w} {
904  global _UnitData
905  set _UnitData(input:value) $_UnitData(saved)
906  $w.values.input.ent selection clear
907  $w.values.input.ent icursor end
908}
909
910proc units:copy {w} {
911  global _UnitData
912  clipboard clear
913  clipboard append $_UnitData(output:value)
914}
915
916