Error processing request

Parameters

CONTENT_LENGTH0
REQUEST_METHODGET
REQUEST_URI/revision/A+Pair+of+Tachometer-style+Meters+---+for+Memory+and+Swap?V=25
QUERY_STRINGV=25
CONTENT_TYPE
DOCUMENT_URI/revision/A+Pair+of+Tachometer-style+Meters+---+for+Memory+and+Swap
DOCUMENT_ROOT/var/www/nikit/nikit/nginx/../docroot
SCGI1
SERVER_PROTOCOLHTTP/1.1
HTTPSon
REMOTE_ADDR172.70.179.104
REMOTE_PORT32538
SERVER_PORT4443
SERVER_NAMEwiki.tcl-lang.org
HTTP_HOSTwiki.tcl-lang.org
HTTP_CONNECTIONKeep-Alive
HTTP_ACCEPT_ENCODINGgzip, br
HTTP_X_FORWARDED_FOR3.128.189.213
HTTP_CF_RAY88d4896f5a8763a2-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/A+Pair+of+Tachometer%2Dstyle+Meters+%2D%2D%2D+for+Memory+and+Swap?V=25
HTTP_CF_CONNECTING_IP3.128.189.213
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 {A Pair of Tachometer-style Meters --- for Memory and Swap} \[uniquename\]\ -\ 2013sep01\n\nA\ couple\ of\ months\ ago,\ I\ put\ it\ on\ my\ 'to\ do'\ list\ to\ implement\ some\npractical\ applications\ for\ the\ nice\ 'tachometer\ style'\ meter\ for\ which\nMarco\ Maggi\ provided\ a\ demo\ script\ \[http://wiki.tcl.tk/9107\]\ back\ in\ 2003.\n\nOne\ of\ the\ first\ applications\ of\ the\ meter\ that\ I\ had\ in\ mind\ was\ to\nshow\ memory\ and\ swap\ used\ on\ my\ computer\ at\ any\ time\ ---\ by\ using\ a\nTk\ script\ as\ a\ 'wrapper'\ for\ the\ 'free'\ command,\ which\ is\ available\ on\nmy\ operating\ system\ (Ubuntu\ 9.10,\ 2009\ October,\ 'Karmic\ Koala').\n\nSince\ the\ 'free'\ command\ (or\ a\ command\ returning\ similar\ data)\ is\nprobably\ available\ on\ most\ Linux,\ Unix,\ and\ BSD\ systems\ ---\ and\ since\nthe\ Apple\ Mac\ operating\ system\ is\ based\ on\ a\ BSD\ system,\ this\ utility\nis\ probably\ usable\ (with\ very\ little\ change)\ on\ Linux-Unix-BSD-Mac\ systems.\n\nBesides\ showing\ two\ 'tachometer\ style'\ meters,\ side\ by\ side,\ on\ two\nTk\ 'canvas'\ widgets\ ---\ I\ originally\ wanted\ to\ provide\ a\ 'scale'\ widget\non\ the\ GUI,\ by\ which\ the\ user\ could\ specify\ at\ any\ time\ a\ new\ 'sampling\ rate'\n(actually,\ a\ 'wait-time'\ =\ 'wave-length',\ rather\ than\ a\ 'frequency').\n\nBut\ I\ found\ that\ there\ were\ technical\ problems\ with\ using\ the\ wait-time.\nNamely,\ in\ my\ attempt\ at\ implementation,\ the\ GUI\ became\ essentially\nnon-interactive\ during\ the\ wait\ time.\n\nSo,\ for\ now,\ I\ have\ supplied\ a\ 'Refresh'\ button\ on\ the\ GUI,\ so\ that\ the\nuser\ can\ request\ at\ ANY\ TIME,\ a\ new\ set\ of\ memory\ and\ swap\ values\ to\nbe\ displayed\ on\ the\ GUI.\n\nIn\ putting\ together\ the\ code\ for\ this\ GUI,\ I\ drew\ heavily\ on\ the\n'shadow-circle'\ technique\ of\ Marco\ Maggi\ to\ make\ nice\ looking\ meters.\nAnd\ I\ included\ a\ 'red-line'\ (danger)\ area\ on\ the\ meters,\ like\ he\ did.\n\nAfter\ several\ iterations\ (including\ restructuring\ the\ procs\ a\ few\ times\nand\ revising\ the\ widgets\ available\ on\ the\ GUI),\ I\ ended\ up\ with\ the\ GUI\nseen\ in\ the\ following\ image.\n\n\[meters_MEMandSWAP_initial_screenshot_412x300.jpg\]\n\nWhen\ the\ GUI\ first\ comes\ up,\ the\ two\ meters\ (their\ canvases)\ are\ sized\nat\ 200x200\ pixels\ ---\ and\ the\ data\ shown\ is\ based\ on\ an\ initial\ execution\nof\ the\ 'free'\ command.\n\nOne\ rather\ unique\ thing\ about\ this\ implementation\ of\ the\ meters\n(something\ not\ done\ by\ Maggi\ in\ his\ demo)\ is\ that\ the\ window\ and\ the\ncanvases\ and\ the\ meters\ are\ resizable.\ In\ other\ words,\ I\ spent\ quite\na\ bit\ of\ effort\ in\ converting\ Maggi's\ procs\n\ \ \ *\ FROM\ using\ hard-coded\ numbers\ for\ making\ the\ meters\ and\ their\ needles\n\ \ \ *\ TO\ using\ variables\ that\ work\ off\ of\ queries\ on\ the\ current\ size\ of\ frame\ and\ canvas\ widgets.\n\nSo\ the\ user\ is\ able\ to\ resize\ the\ window\ and\ click\ on\ the\ 'Refresh'\ button\nto\ get\ a\ bigger\ version\ of\ the\ meters\ and\ the\ needle\ position\ ---\ as\nyou\ can\ see\ in\ the\ following\ image.\n\n\[meters_MEMandSWAP_large_screenshot_635x410.jpg\]\n\nI\ had\ hoped\ to\ come\ up\ with\ a\ technique\ to\ avoid\ the\ 'aliasing'\ effect\non\ the\ needles\ ---\ but\ you\ can\ see\ in\ this\ image\ that,\ for\ certain\nangles\ of\ the\ needles,\ there\ is\ a\ pronounced\ 'stair-step'\ effect.\n\nHowever,\ as\ 'retina\ display'\ monitors\ come\ into\ use\ more\ and\ more\n(with\ resolutions\ above\ about\ 2000x1500\ pixels),\ even\ without\ changing\nthe\ needle-drawing\ code\ in\ this\ script,\ you\ may\ find\ that\ the\n'jaggies'\ are\ hard\ to\ see.\ (I\ do\ not\ have\ such\ a\ monitor\ yet,\ so\ I\ncannot\ say\ for\ sure.)\n\n------\n\nCAPTURING\ THE\ GENERATED\ IMAGE:\n\nWhen\ you\ get\ an\ image\ that\ you\ want\ to\ save\ ---\ say,\ to\ report\ a\nmemory-leak\ problem\ for\ some\ software\ ---\ a\ screen/window\ capture\nutility\ (like\ 'gnome-screenshot'\ on\ Linux)\ can\ be\ used\ to\ capture\nthe\ GUI\ image\ in\ a\ PNG\ or\ GIF\ file,\ say.\n\nIf\ necessary,\ an\ image\ editor\ (like\ 'mtpaint'\ on\ Linux)\ncan\ be\ used\ to\ crop\ the\ window\ capture\ image.\ \ The\ image\ncould\ also\ be\ down-sized\ ---\ say\ to\ make\ a\ smaller\ image\ suitable\ for\npresentation\ in\ an\ email\ or\ on\ a\ web\ page.\n\n------\n\nA\ LITTLE\ MEMORY\ EXPERIMENT:\n\nTo\ get\ the\ memory\ figures\ to\ change,\ I\ tried\ bringing\ up\ an\ instance\nof\ the\ Seamonkey\ web\ browser\ on\ my\ computer\ and\ then\ clicking\ on\ the\n'Refresh'\ button.\ I\ found\ that\ for\ each\ new\ instance\ of\ Seamonkey\nthat\ I\ started\ (I\ started\ about\ seven),\ the\ memory\ usage\ went\ up\nabout\ 2\ to\ 10\ Megabytes.\n\nAt\ that\ level\ of\ memory\ consumption,\ the\ percent-needle\ hardly\ moved,\nbecause\ 10/3000\ is\ less\ than\ one-half\ of\ one\ percent.\n\n------\n\n'''The\ code'''\n\nBelow,\ I\ provide\ the\ Tk\ script\ code\ for\ this\ 'memory-and-swap\ in\ tachometers'\ndisplay\ utility.\n\nI\ follow\ my\ usual\ 'canonical'\ structure\ for\ Tk\ code\ for\ this\ Tk\ script:\n\n\ \ 0)\ Set\ general\ window\ &\ widget\ parms\ (win-name,\ win-position,\n\ \ \ \ \ win-color-scheme,\ fonts,\ widget-geometry-parms,\ win-size-control,\n\ \ \ \ \ text-array-for-labels-etc).\n\n\ \ 1a)\ Define\ ALL\ frames\ (and\ sub-frames,\ if\ any).\n\ \ 1b)\ Pack\ \ \ ALL\ frames\ and\ sub-frames.\n\n\ \ 2)\ Define\ &\ pack\ all\ widgets\ in\ the\ frames,\ frame\ by\ frame.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Within\ each\ frame,\ define\ ALL\ the\ widgets.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Then\ pack\ the\ widgets.\n\n\ \ 3)\ Define\ keyboard\ and\ mouse/touchpad/touch-sensitive-screen\ action\n\ \ \ \ \ BINDINGS,\ if\ needed.\n\n\ \ 4)\ Define\ PROCS,\ if\ needed.\n\n\ \ 5)\ Additional\ GUI\ initialization\ (typically\ with\ one\ or\ more\ of\n\ \ \ \ \ the\ procs),\ if\ needed.\n\nThis\ Tk\ coding\ structure\ is\ discussed\ in\ more\ detail\ on\ the\ page\n\[A\ Canonical\ Structure\ for\ Tk\ Code\ ---\ and\ variations\].\n\nThis\ structure\ makes\ it\ easy\ for\ me\ to\ find\ code\ sections\ ---\ while\ngenerating\ and\ testing\ a\ Tk\ script,\ and\ when\ looking\ for\ code\ snippets\nto\ include\ in\ other\ scripts\ (code\ re-use).\n\nI\ call\ your\ attention\ to\ step-zero.\nOne\ new\ thing\ that\ I\ have\ started\ doing\ recently\ is\ using\ a\ text-array\nfor\ text\ in\ labels,\ buttons,\ and\ other\ widgets\ in\ the\ GUI.\nThis\ can\ make\ it\ easier\ for\ people\ to\ internationalize\ my\ scripts.\nI\ will\ be\ using\ a\ text-array\ like\ this\ in\ most\ of\ my\ scripts\ in\ the\ future.\n\n------\n\n'''Experimenting\ with\ the\ GUI'''\n\nAs\ in\ all\ my\ scripts\ that\ use\ the\ 'pack'\ geometry\ manager\ (which\ is\ all\nof\ my\ 100-plus\ scripts,\ so\ far),\ I\ provide\ the\ four\ main\ pack\ parameters\n---\ '-side',\ '-anchor',\ '-fill',\ '-expand'\ ---\ on\ all\ of\ the\ 'pack'\ncommands\ for\ the\ frames\ and\ widgets.\n\nThat\ helps\ me\ when\ I\ am\ initially\ testing\ the\ behavior\ of\ a\ GUI\n(the\ various\ widgets\ within\ it)\ as\ I\ resize\ the\ main\ window.\n\nI\ think\ that\ I\ have\ used\ a\ pretty\ nice\ choice\ of\ the\ 'pack'\ parameters.\nThe\ label\ and\ button\ widgets\ stay\ fixed\ in\ size\ and\ relative-location\nif\ the\ window\ is\ re-sized\ ---\ while\ the\ two\ canvas\ areas\ (without\ scroll\ bars)\nexpand/contract\ whenever\ the\ window\ is\ re-sized,\ and\ the\ 'Refresh'\ button\nis\ clicked.\n\nThe\ meters\ expand/contract\ when\ the\ window\ is\ re-sized\ ---\ but\ probably\nnot\ always\ in\ a\ way\ you\ would\ expect.\ Occasionally,\ you\ may\ need\ to\ tug\nthe\ borders\ of\ the\ window\ to\ center\ the\ meters\ in\ a\ way\ that\ suits\ you.\n\nYou\ can\ experiment\ with\ the\ \ '-side',\ '-anchor',\ '-fill',\nand\ '-expand'\ parameters\ on\ the\ 'pack'\ commands\ for\ the\ various\nframes\ and\ widgets\ ---\ to\ get\ the\ widget\ behavior\ that\ you\ want.\n\nAnd\ you\ can\ look\ into\ the\ code\ that\ is\ drawing\ the\ meters\ to\ see\ if\ you\ncan\ devise\ meter-resizing\ behavior\ that\ pleases\ you\ more.\n\n___\n\nAdditional\ experimentation:\ You\ might\ want\ to\ change\ the\ fonts\ used\ for\nthe\ various\ GUI\ widgets.\ For\ example,\ you\ could\ change\ '-weight'\nfrom\ 'bold'\ to\ 'normal'\ ---\ or\ '-slant'\ from\ 'roman'\ to\ 'italic'.\nOr\ change\ font\ families.\n\nIn\ fact,\ you\ may\ NEED\ to\ change\ the\ font\ families,\ because\nthe\ families\ I\ used\ may\ not\ be\ available\ on\ your\ computer\ ---\nand\ the\ default\ font\ that\ the\ 'wish'\ interpreter\ chooses\ may\ not\nbe\ very\ pleasing.\n\nI\ use\ variables\ to\ set\ geometry\ parameters\ of\ widgets\ ---\nparameters\ such\ as\ border-widths\ and\ padding.\ And\ I\ have\ included\nthe\ '-relief'\ parameter\ on\ the\ definitions\ of\ frames\ and\ widgets.\nFeel\ free\ to\ experiment\ with\ those\ 'appearance'\ parameters\ as\ well.\n\n------\n\n'''Some\ features\ in\ the\ code'''\n\nThat\ said,\ here's\ the\ code\ ---\ with\ plenty\ of\ comments\ to\ describe\nwhat\ most\ of\ the\ code-sections\ are\ doing.\n\nYou\ can\ look\ at\ the\ top\ of\ the\ PROCS\ section\ of\ the\ code\ to\ see\ a\nlist\ of\ the\ procs\ used\ in\ this\ script,\ along\ with\ brief\ descriptions\nof\ how\ they\ are\ called\ and\ what\ they\ do.\n\nThe\ main\ procs\ are\n\n\ \ \ 'make_tachometers'\ -\ to\ draw\ 2\ meters\ within\ their\ 2\ Tk\ (square)\ canvases.\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (We\ may\ allow\ the\ 2\ canvases\ to\ resize\ according\ to\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ a\ resizing\ of\ the\ window.\ This\ proc\ will\ set\ the\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ SQUARE\ size\ of\ the\ 2\ canvases\ according\ to\ the\ current\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size\ of\ the\ frame\ containing\ the\ 2\ canvases.)\n\n\ \ \ 'make_one_tachometer'\ -\ called\ by\ 'make_tachometers',\ to\ make\ each\ meter.\n\n\ \ \ 'draw_rivet'\ \ \ \ \ \ -\ called\ by\ 'make_one_tachometer',\ 4\ times,\ to\ put\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rivets\ in\ 4\ corners\ around\ a\ meter.\n\n\ \ \ 'draw_circle_shadow'\ \ -\ called\ by\ 'make_one_tachometer'\ to\ put\ a\ shadowed\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ edge\ around\ the\ circle\ that\ makes\ the\ meter.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Also\ called\ to\ help\ make\ a\ 'pin'\ in\ the\ center\ of\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ meter\ to\ hold\ the\ needle.\ Also\ called\ to\ make\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ 4\ rivets.\n\n\ \ \ 'update_needles'\ \ \ \ \ \ -\ to\ update\ the\ needles\ on\ the\ 2\ meters.\n\n\ \ \ 'update_one_needle'\ \ \ -\ called\ by\ 'update_needles',\ to\ draw\ each\ needle.\n\n\ \ \ 'Refresh'\ \ \ \ \ \ \ \ \ \ \ \ \ -\ called\ by\ 'Refresh'\ button.\ Runs\ 'make_tachometers'\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ and\ 'update_needles'.\ \ \n\n\ \ \ 'popup_msgVarWithScroll'\ -\ called\ by\ the\ 'Help'\ button,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ to\ show\ text\ in\ variable\ \$HELPtext.\n\nThanks\ to\ Marco\ Maggi\ whose\ 'shadow-circle'\ drawing\ technique\ and\ code\nmade\ this\ script\ much\ easier\ to\ write.\n\n-----\n\nIt\ is\ my\ hope\ that\ the\ copious\ comments\ in\ the\ code\ will\ help\ Tcl-Tk\ncoding\ 'newbies'\ get\ started\ in\ making\ GUI's\ like\ this.\n\nWithout\ the\ comments,\ potential\ young\ Tcler's\ might\ be\ tempted\ to\nreturn\ to\ their\ iPhones\ and\ iPads\ and\ iPods\ ---\ to\ watch\ videos\ of\nskydiving\ free\ falls\ gone\ scarily\ wrong.\ (Anyone\ see\ the\ video\ of\nthe\ old\ grandmother\ who\ almost\ slips\ out\ of\ the\ harness\ and\ grasp\ of\ the\nskydiving\ instructor\ who\ no\ doubt\ assured\ her\ that\ there's\ nothing\nto\ worry\ about?)\n\n------\n\n<<discussion>>Code\ for\ Tk\ script\ 'meters_memory_swap.tk'\ :\n\n======\n\n#!/usr/bin/wish\ -f\n##+########################################################################\n##\n##\ SCRIPT:\ meters_memory_swap.tk\n##\n##\ PURPOSE:\ This\ script\ is\ meant\ to\ show\ a\ GUI\ that\ holds\ a\ pair\ of\n##\ \ \ \ \ \ \ \ \ \ tachometer-style\ meters.\ The\ needles\ on\ the\ meters\ can\ be\ updated\n##\ \ \ \ \ \ \ \ \ \ periodically\ to\ show\ the\ amount\ of\ memory\ and\ swap\ in\ use.\n##\n##\ \ \ \ \ \ \ \ \ \ This\ script\ was\ developed\ on\ Linux\ and\ uses\ the\ 'free'\n##\ \ \ \ \ \ \ \ \ \ command\ to\ periodically\ get\ the\ memory\ and\ swap\ data\ to\n##\ \ \ \ \ \ \ \ \ \ determine\ where\ to\ relocate\ the\ position\ of\ the\ needles.\n##\n##+################\n##\ GUI\ DESCRIPTION:\n##\n##\ \ \ \ \ \ \ \ \ This\ script\ provides\ a\ Tk\ GUI\ with\ the\ following\ widgets.\n##\n##\ \ \ \ \ \ \ \ \ 1)\ There\ is\ an\ 'fRbuttons'\ frame\ to\ hold\ BUTTONS\ such\ as\n##\ \ \ \ \ \ \ \ \ \ \ \ 'Exit'\ and\ 'Help'\ buttons\ ---\ as\ well\ as\ a\ 'Refresh'\n##\ \ \ \ \ \ \ \ \ \ \ \ button.\n##\n##\ \ \ \ \ \ \ \ \ \ \ \ (Someday,\ I\ would\ like\ to\ implement\ a\ SCALE\ widget\ for\ the\n##\ \ \ \ \ \ \ \ \ \ \ \ \ user\ to\ set\ a\ 'wait-seconds'\ for\ auto-refresh\ of\ the\ meters\ ---\n##\ \ \ \ \ \ \ \ \ \ \ \ \ in\ seconds\ ---\ down\ to\ tenths\ of\ seconds,\ and\ up\ to\ multiple\n##\ \ \ \ \ \ \ \ \ \ \ \ \ minutes.\ But\ I\ hit\ technical\ problems.\ Perhaps\ later.)\n##\n##\ \ \ \ \ \ \ \ \ 2)\ There\ is\ an\ 'fRcanvases'\ frame\ to\ contain\ 2\ CANVAS\ widgets\ that\n##\ \ \ \ \ \ \ \ \ \ \ \ hold\ the\ two\ meter\ images,\ in\ 2\ SQUARE\ canvases,\ side\ by\ side.\n##\ \ \ \ \ \ \ \ \ \ \ \ Also\ the\ 'fRcanvases'\ frame\ holds\ some\ LABEL\ widgets,\ to\ show\n##\ \ \ \ \ \ \ \ \ \ \ \ TOTAL-and-USED\ MEMORY\ and\ TOTAL-and-USED\ SWAP,\ as\ text\ items.\n##\n##+################################\n##\ METHOD\ USED\ to\ update\ the\ meters:\n##\n##\ \ \ \ A\ Tcl\ 'exec'\ command\ calls\ on\ a\ separate\ shell\ script\ that\ uses\n##\ \ \ \ the\ 'free'\ command\ to\ get\ the\ memory\ and\ swap\ data\ and\n##\ \ \ \ extract-and-format\ the\ data\ for\ return\ to\ this\ Tk\ script.\n##\n##+#######################\n##\ CAPTURING\ THE\ GUI\ IMAGE:\n##\n##\ \ \ A\ screen/window\ capture\ utility\ (like\ 'gnome-screenshot'\n##\ \ \ on\ Linux)\ can\ be\ used\ to\ capture\ the\ GUI\ image\ in\ a\ PNG\n##\ \ \ or\ GIF\ file,\ say.\n##\n##\ \ \ If\ necessary,\ an\ image\ editor\ (like\ 'mtpaint'\ on\ Linux)\n##\ \ \ can\ be\ used\ to\ crop\ the\ window\ capture\ image.\ \ The\ image\n##\ \ \ could\ also\ be\ down-sized\ ---\ say\ to\ make\ a\ smaller\ image\n##\ \ \ suitable\ for\ use\ in\ a\ web\ page\ or\ an\ email.\n##\n##+#######################################################################\n##\ 'CANONICAL'\ STRUCTURE\ OF\ THIS\ CODE:\n##\n##\ \ 0)\ Set\ general\ window\ parms\ (win-name,\ win-position,\ win-color-scheme,\n##\ \ \ \ \ fonts,\ widget-geom-parms,\ win-size-control,\ text-array-for-labels-etc).\n##\n##\ \ 1a)\ Define\ ALL\ frames\ (and\ sub-frames,\ if\ any).\n##\ \ 1b)\ Pack\ the\ frames.\n##\n##\ \ 2)\ Define\ &\ pack\ all\ widgets\ in\ the\ frames,\ frame\ by\ frame.\n##\ \ \ \ \ After\ all\ the\ widgets\ for\ a\ frame\ are\ defined,\ pack\ them\ in\ the\ frame.\n##\n##\ \ 3)\ Define\ keyboard\ or\ mouse/touchpad/touch-sensitive-screen\ 'event'\n##\ \ \ \ \ BINDINGS,\ if\ needed.\n##\n##\ \ 4)\ Define\ PROCS,\ if\ needed.\n##\n##\ \ 5)\ Additional\ GUI\ INITIALIZATION\ (typically\ with\ one\ or\ more\ of\n##\ \ \ \ \ the\ procs),\ if\ needed.\n##\n##+#################################\n##\ Some\ detail\ of\ the\ code\ structure\ of\ this\ particular\ script:\n##\n##\ \ 1a)\ Define\ ALL\ frames:\n##\ \n##\ \ \ Top-level\ :\n##\ \ \ \ \ \ '.fRbuttons'\ \ -\ to\ contain\ a\ widget\ to\ set\ the\ refresh-rate,\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ as\ well\ as\ contain\ 'Exit'\ and\ 'Help'\ buttons.\n##\ \ \ \ \ \ '.fRcanvases'\ -\ to\ contain\ 2\ canvas\ widgets,\ which\ will\ display\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ two\ meters,\ side-by-side.\n##\n##\ \ \ Sub-frames:\n##\ \ \ \ \ \ \ '.fRcanvases.fRcanvas1'\ -\ for\ 2\ label\ widgets\ &\ 1\ canvas\ widget\n##\ \ \ \ \ \ \ '.fRcanvases.fRcanvas2'\ -\ for\ 2\ label\ widgets\ &\ 1\ canvas\ widget\n##\n##\ \ 1b)\ Pack\ ALL\ frames.\n##\n##\ \ 2)\ Define\ &\ pack\ all\ widgets\ in\ the\ frames\ --\ basically\ going\ through\n##\ \ \ \ \ frames\ &\ their\ interiors\ in\ \ left-to-right,\ or\ top-to-bottom\ order.\n##\n##\ \ 3)\ Define\ BINDINGS:\ \ none\n##\n##\ \ 4)\ Define\ PROCS:\n##\n##\ \ \ \ 'make_tachometers'\ -\ to\ draw\ 2\ meters\ within\ their\ 2\ Tk\ (square)\ canvases.\n##\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (We\ may\ allow\ the\ 2\ canvases\ to\ resize\ according\ to\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ a\ resizing\ of\ the\ window.\ This\ proc\ will\ set\ the\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ SQUARE\ size\ of\ the\ 2\ canvases\ according\ to\ the\ current\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size\ of\ the\ frame\ containing\ the\ 2\ canvases.)\n##\n##\ \ \ \ 'make_one_tachometer'\ -\ called\ by\ 'make_tachometers',\ to\ make\ each\ meter.\n##\n##\ \ \ \ 'draw_rivet'\ \ \ \ \ \ -\ called\ by\ 'make_one_tachometer',\ 4\ times,\ to\ put\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rivets\ in\ 4\ corners\ around\ a\ meter.\n##\n##\ \ \ \ 'draw_circle_shadow'\ \ -\ called\ by\ 'make_one_tachometer'\ to\ put\ a\ shadowed\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ edge\ around\ the\ circle\ that\ makes\ the\ meter.\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Also\ called\ to\ help\ make\ a\ 'pin'\ in\ the\ center\ of\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ meter\ to\ hold\ the\ needle.\ Also\ called\ to\ make\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ 4\ rivets.\n##\n##\ \ \ \ 'update_needles'\ \ \ \ \ \ -\ to\ update\ the\ needles\ on\ the\ 2\ meters.\n##\n##\ \ \ \ 'update_one_needle'\ \ \ -\ called\ by\ 'update_needles',\ to\ draw\ each\ needle.\n##\n##\ \ \ \ 'Refresh'\ \ \ \ \ \ \ \ \ \ \ \ \ -\ called\ by\ 'Refresh'\ button.\ Runs\ 'make_tachometers'\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ and\ 'update_needles'.\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n##\n##\ \ \ 'popup_msgVarWithScroll'\ -\ called\ by\ 'Help'\ button\ to\ show\ HELPtext\ var.\n##\ \ \ \ \ \ \ \ \ \n##\n##\ \ 5)\ Additional\ GUI\ Initialization:\n##\ \ \ \ \ \ \ \ -\ call\ 'make_tachometers'\ to\ put\ the\ 2\ meters\ on\ the\ canvas\n##\ \ \ \ \ \ \ \ -\ call\ 'update_needles'\ ---\ to\ initialize\ the\ needle\ locations.\n##\n##+#######################################################################\n##\ DEVELOPED\ WITH:\ Tcl-Tk\ 8.5\ on\ Ubuntu\ 9.10\ (2009-october,\ 'Karmic\ Koala')\n##\n##\ \ \ \$\ wish\n##\ \ \ %\ puts\ \"\$tcl_version\ \$tk_version\"\n##\n##\ showed\n##\ \ \ \ \ 8.5\ 8.5\n##\ but\ this\ script\ should\ work\ in\ most\ previous\ 8.x\ versions,\ and\ probably\n##\ even\ in\ some\ 7.x\ versions\ (if\ font\ handling\ is\ made\ 'old-style').\n##+#######################################################################\n##\ MAINTENANCE\ HISTORY:\n##\ Started\ by:\ Blaise\ Montandon\ 2013jul29\ Started\ the\ basic\ code\ of\ the\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ script\ based\ on\ the\ tachometer\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ demo\ script\ by\ Marco\ Maggi\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ at\ http://wiki.tcl.tk/9107\n##\ Changed\ by:\ Blaise\ Montandon\ 2013aug30\ Get\ most\ of\ the\ GUI\ working,\ using\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ an\ appropriate\ hierarchy\ of\ procs.\n##\ Changed\ by:\ Blaise\ Montandon\ 2013sep01\ Settled\ on\ using\ a\ 'Refresh'\ button,\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ instead\ of\ a\ scale\ widget\ with\ a\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ WAITseconds\ variable.\n##+########################################################################\n\n##+######################################################\n##\ Set\ WINDOW\ TITLE\ and\ POSITION.\n##+######################################################\n\nwm\ title\ \ \ \ .\ \"Percent\ of\ Total\ Memory\ &\ Swap\ in\ Use\"\nwm\ iconname\ .\ \"MemSwap\"\n\nwm\ geometry\ .\ +15+30\n\n\n##+######################################################\n##\ Set\ the\ COLOR\ SCHEME\ for\ the\ window\ and\ its\ widgets\ ---\n##\ such\ as\ listbox\ and\ entry\ field\ background\ color.\n##+######################################################\n\ntk_setPalette\ \"#e0e0e0\"\n\n#\ set\ listboxBKGD\ \"#ffffff\"\n#\ set\ entryBKGD\ \"#ffffff\"\n\ \ set\ scaleBKGD\ \"#f0f0f0\"\n\n##+########################################################\n##\ DEFINE\ (temporary)\ FONT\ NAMES.\n##\n##\ We\ use\ a\ VARIABLE-WIDTH\ font\ for\ text\ on\ LABEL\ and\n##\ BUTTON\ widgets.\n##\n##\ We\ use\ a\ FIXED-WIDTH\ font\ for\ LISTBOX\ lists,\n##\ for\ Help-text\ in\ a\ TEXT\ widget,\ and\ for\n##\ the\ text\ in\ ENTRY\ fields,\ if\ any.\n##+########################################################\n\nfont\ create\ fontTEMP_varwidth\ \\\n\ \ \ -family\ \{comic\ sans\ ms\}\ \\\n\ \ \ -size\ -14\ \\\n\ \ \ -weight\ bold\ \\\n\ \ \ -slant\ roman\n\nfont\ create\ fontTEMP_SMALL_varwidth\ \\\n\ \ \ -family\ \{comic\ sans\ ms\}\ \\\n\ \ \ -size\ -12\ \\\n\ \ \ -weight\ bold\ \\\n\ \ \ -slant\ roman\n\n##\ Some\ other\ possible\ (similar)\ variable\ width\ fonts:\n##\ \ Arial\n##\ \ Bitstream\ Vera\ Sans\n##\ \ DejaVu\ Sans\n##\ \ Droid\ Sans\n##\ \ FreeSans\n##\ \ Liberation\ Sans\n##\ \ Nimbus\ Sans\ L\n##\ \ Trebuchet\ MS\n##\ \ Verdana\n\n\nfont\ create\ fontTEMP_fixedwidth\ \ \\\n\ \ \ -family\ \{liberation\ mono\}\ \\\n\ \ \ -size\ -14\ \\\n\ \ \ -weight\ bold\ \\\n\ \ \ -slant\ roman\n\nfont\ create\ fontTEMP_SMALL_fixedwidth\ \ \\\n\ \ \ -family\ \{liberation\ mono\}\ \\\n\ \ \ -size\ -12\ \\\n\ \ \ -weight\ bold\ \\\n\ \ \ -slant\ roman\n\n##\ Some\ other\ possible\ fixed\ width\ fonts\ (esp.\ on\ Linux):\n##\ \ Andale\ Mono\n##\ \ Bitstream\ Vera\ Sans\ Mono\n##\ \ Courier\ 10\ Pitch\n##\ \ DejaVu\ Sans\ Mono\n##\ \ Droid\ Sans\ Mono\n##\ \ FreeMono\n##\ \ Nimbus\ Mono\ L\n##\ \ TlwgMono\n\n\n##+###########################################################\n##\ SET\ GEOM\ VARS\ FOR\ THE\ VARIOUS\ WIDGET\ DEFINITIONS.\n##\ (e.g.\ width\ and\ height\ of\ canvas,\ and\ padding\ for\ Buttons)\n##+###########################################################\n\n##\ CANVAS\ widget\ geom\ settings:\n\nset\ initCanWidthPx\ \ 200\nset\ initCanHeightPx\ 200\n\nset\ minCanWidthPx\ \ 24\nset\ minCanHeightPx\ 24\n\n#\ set\ BDwidthPx_canvas\ 2\n\ \ set\ BDwidthPx_canvas\ 0\n\n\n##\ BUTTON\ widget\ geom\ settings:\n\nset\ PADXpx_button\ 0\nset\ PADYpx_button\ 0\nset\ BDwidthPx_button\ 2\n\n\n##\ LABEL\ widget\ geom\ settings:\n\nset\ PADXpx_label\ 0\nset\ PADYpx_label\ 0\nset\ BDwidthPx_label\ 2\n\n\n##\ SCALE\ widget\ geom\ parameters:\n\nset\ BDwidthPx_scale\ 2\nset\ initScaleLengthPx\ 200\nset\ scaleThicknessPx\ 10\n\n\n##+######################################################################\n##\ Set\ a\ MIN-SIZE\ of\ the\ window\ (roughly).\n##\n##\ For\ WIDTH,\ allow\ for\ the\ min-width\ of\ the\ '.fRbuttons'\ and\ '.fRcanvas'\n##\ frames\ ---\ at\ least,\ the\ widgets\ in\ the\ 'fRbuttons'\ frame.\n##\n##\ For\ HEIGHT,\ allow\ for\ the\ stacked\ frames:\n##\ \ \ \ \ \ \ \ \ \ \ \ 2\ chars\ \ high\ for\ the\ '.fRbuttons'\ frame,\n##\ \ at\ least\ 50\ pixels\ high\ for\ the\ '.fRcanvas'\ \ frame.\n##+#####################################################################\n\n##\ FOR\ WIDTH:\n\nset\ minWidthPx\ \[font\ measure\ fontTEMP_varwidth\ \\\n\ \ \ \"\ Exit\ \ Help\ \ Refresh\ \"\]\n\n##\ If\ we\ had\ used\ the\ scale\ widget,\ we\ would\ accomodate\ and\ label\n##\ and\ add\ pixels\ for\ length\ of\ the\ scale\ widget,\ at\ least\ 100.\n##\n##\ For\ now,\ we\ simply\ add\ some\ pixels\ to\ account\ for\ right-left-size\ of\n##\ window-manager\ decoration\ (~8\ pixels)\ and\ some\ pixels\ for\n##\ frame/widget\ borders\ (~3\ widgets\ x\ 4\ pixels/widget\ =\ 12\ pixels).\n\nset\ minWinWidthPx\ \[expr\ \{20\ +\ \$minWidthPx\}\]\n\n\n##\ For\ HEIGHT\ ---\ for\n##\ \ \ \ 2\ char\ \ \ high\ for\ 'fRbuttons'\n##\ \ \ 50\ pixels\ high\ for\ 'fRcanvas'\n\nset\ charHeightPx\ \[font\ metrics\ fontTEMP_varwidth\ -linespace\]\n\nset\ minWinHeightPx\ \[expr\ \{2\ *\ \$charHeightPx\}\]\n\n##\ Add\ about\ 50\ pixels\ for\ height\ of\ the\ canvas\n##\ AND\ add\ about\ 20\ pixels\ for\ top-bottom\ window\ decoration\ --\n##\ and\ some\ pixels\ for\ top-and-bottom\ of\ frame/widget\ borders\n##\ (~4\ widgets\ x\ 4\ pixels/widget\ =\ 16\ pixels).\n\nset\ minWinHeightPx\ \[expr\ \{86\ +\ \$minWinHeightPx\}\]\n\n\n##\ FOR\ TESTING:\n#\ \ \ puts\ \"minWinWidthPx\ =\ \$minWinWidthPx\"\n#\ \ \ puts\ \"minWinHeightPx\ =\ \$minWinHeightPx\"\n\nwm\ minsize\ .\ \$minWinWidthPx\ \$minWinHeightPx\n\n\n##\ We\ may\ allow\ the\ window\ to\ be\ resizable.\ \ We\ pack\ the\ canvases\n##\ (and\ the\ frames\ that\ contain\ them)\ with\ '-fill\ both\ -expand\ 1'\n##\ so\ that\ the\ canvases\ can\ be\ enlarged\ by\ enlarging\ the\ window.\n\n##\ If\ you\ want\ to\ make\ the\ window\ un-resizable,\ \n##\ you\ can\ use\ the\ following\ statement.\n#\ \ \ wm\ resizable\ .\ 0\ 0\n\n\n##+##############################################################\n##\ Set\ a\ TEXT-ARRAY\ to\ hold\ text\ for\ buttons\ &\ labels\ on\ the\ GUI.\n##\ \ \ \ \ NOTE:\ This\ can\ aid\ INTERNATIONALIZATION.\ This\ array\ can\n##\ \ \ \ \ \ \ \ \ \ \ be\ set\ according\ to\ a\ nation/region\ parameter.\n##+##############################################################\n\n##\ if\ \{\ \"\$VARlocale\"\ ==\ \"en\"\}\n\n##\ For\ '.fRbuttons'\ frame:\n\nset\ aRtext(buttonEXIT)\ \ \"Exit\"\nset\ aRtext(buttonHELP)\ \ \"Help\"\n\nset\ aRtext(buttonREFRESH)\ \ \"Refresh\"\n\n#\ set\ aRtext(labelSCALE)\ \ \"Refresh\ rate\n#\ (seconds)\ :\"\n\n##\ END\ OF\ \ if\ \{\ \"\$VARlocale\"\ ==\ \"en\"\}\n\n\n##+################################################################\n##\ DEFINE\ *ALL*\ THE\ FRAMES:\n##\n##\ \ \ Top-level\ :\ '.fRbuttons'\ ,\ '.fRcanvases'\n##\n##\ \ \ Sub-frames:\ '.fRcanvases.fRcanvas1'\ \ '.fRcanvases.fRcanvas2'\ \n##+################################################################\n\n##\ FOR\ TESTING:\ (to\ see\ size\ of\ frames\ as\ window\ is\ resized)\n#\ set\ BDwidth_frame\ 2\n#\ set\ RELIEF_frame\ raised\n\n\ \ set\ BDwidth_frame\ 0\n\ \ set\ RELIEF_frame\ flat\n\nframe\ .fRbuttons\ \ \ -relief\ \$RELIEF_frame\ \ -bd\ \$BDwidth_frame\nframe\ .fRcanvases\ \ -relief\ \$RELIEF_frame\ \ -bd\ \$BDwidth_frame\n\nframe\ .fRcanvases.fRcanvas1\ \ -relief\ raised\ \ -bd\ 2\nframe\ .fRcanvases.fRcanvas2\ \ -relief\ raised\ \ -bd\ 2\n\n\n##+##############################\n##\ PACK\ the\ FRAMES.\ \n##+##############################\n\npack\ .fRbuttons\ \\\n\ \ \ -side\ top\ \\\n\ \ \ -anchor\ nw\ \\\n\ \ \ -fill\ x\ \\\n\ \ \ -expand\ 0\n\npack\ .fRcanvases\ \\\n\ \ \ -side\ top\ \\\n\ \ \ -anchor\ nw\ \\\n\ \ \ -fill\ both\ \\\n\ \ \ -expand\ 1\n\npack\ .fRcanvases.fRcanvas1\ \\\n\ \ \ -side\ left\ \\\n\ \ \ -anchor\ nw\ \\\n\ \ \ -fill\ both\ \\\n\ \ \ -expand\ 1\n\npack\ .fRcanvases.fRcanvas2\ \\\n\ \ \ -side\ right\ \\\n\ \ \ -anchor\ ne\ \\\n\ \ \ -fill\ both\ \\\n\ \ \ -expand\ 1\n\n\n\n##+##########################################################\n##\ The\ FRAMES\ ARE\ PACKED.\ START\ PACKING\ WIDGETS\ IN\ THE\ FRAMES.\n##+##########################################################\n\n##+##########################################################\n##\ In\ FRAME\ '.fRbuttons'\ -\n##\ DEFINE-and-PACK\ 'BUTTON'\ WIDGETS\n##\ ---\ Exit,\ Help,\ ...\ ---\ and\ a\ LABEL-AND-SCALE\ widget\ pair\n##\ (for\ changing\ the\ 'refresh\ rate'\ for\ the\ meter\ needles.\n##+##########################################################\n\nbutton\ .fRbuttons.buttEXIT\ \\\n\ \ \ -text\ \"\$aRtext(buttonEXIT)\"\ \\\n\ \ \ -font\ fontTEMP_varwidth\ \\\n\ \ \ -padx\ \$PADXpx_button\ \\\n\ \ \ -pady\ \$PADYpx_button\ \\\n\ \ \ -relief\ raised\ \\\n\ \ \ -bd\ \$BDwidthPx_button\ \\\n\ \ \ -command\ \{set\ loop0or1\ 0\ \;\ exit\}\n\nbutton\ .fRbuttons.buttHELP\ \\\n\ \ \ -text\ \"\$aRtext(buttonHELP)\"\ \\\n\ \ \ -font\ fontTEMP_varwidth\ \\\n\ \ \ -padx\ \$PADXpx_button\ \\\n\ \ \ -pady\ \$PADYpx_button\ \\\n\ \ \ -relief\ raised\ \\\n\ \ \ -bd\ \$BDwidthPx_button\ \\\n\ \ \ -command\ \{popup_msgVarWithScroll\ .topHelp\ \"\$HELPtext\"\}\n\n\nbutton\ .fRbuttons.buttREFRESH\ \\\n\ \ \ -text\ \"\$aRtext(buttonREFRESH)\"\ \\\n\ \ \ -font\ fontTEMP_varwidth\ \\\n\ \ \ -padx\ \$PADXpx_button\ \\\n\ \ \ -pady\ \$PADYpx_button\ \\\n\ \ \ -relief\ raised\ \\\n\ \ \ -bd\ \$BDwidthPx_button\ \\\n\ \ \ -command\ \{Refresh\}\n\n\n##\ We\ DE-ACTIVATE\ this\ scale\ widget\ until\ a\ way\ of\ using\n##\ the\ WAITseconds\ variable\ can\ be\ devised\ such\ that\n##\ the\ GUI\ does\ not\ become\ unusable\ during\ the\ wait.\n\nif\ \{0\}\ \{\nlabel\ .fRbuttons.labelSCALE\ \\\n\ \ \ -text\ \"\$aRtext(labelSCALE)\"\ \\\n\ \ \ -font\ fontTEMP_SMALL_varwidth\ \\\n\ \ \ -justify\ left\ \\\n\ \ \ -anchor\ w\ \\\n\ \ \ -relief\ flat\ \\\n\ \ \ -padx\ \$PADXpx_label\ \\\n\ \ \ -pady\ \$PADYpx_label\ \\\n\ \ \ -bd\ \$BDwidthPx_label\n\n\n##\ Set\ this\ widget\ var\ in\ the\ GUI\ initialization\ section\n##\ at\ the\ bottom\ of\ this\ script.\n#\ set\ WAITseconds\ 50\n\nscale\ .fRbuttons.scaleSECONDS\ \\\n\ \ \ -from\ 0.1\ -to\ 120.0\ \\\n\ \ \ -resolution\ 0.1\ \\\n\ \ \ -font\ fontTEMP_SMALL_varwidth\ \\\n\ \ \ -variable\ WAITseconds\ \\\n\ \ \ -showvalue\ true\ \\\n\ \ \ -orient\ horizontal\ \\\n\ \ \ -bd\ \$BDwidthPx_scale\ \\\n\ \ \ -length\ \$initScaleLengthPx\ \\\n\ \ \ -width\ \$scaleThicknessPx\n\}\n##\ END\ OF\ if\ \{0\}\ de-activation\ of\ the\ scale\ widget.\n\n\n##\ Pack\ the\ widgets\ in\ frame\ '.fRbutton'.\n\npack\ .fRbuttons.buttEXIT\ \\\n\ \ \ \ \ .fRbuttons.buttHELP\ \\\n\ \ \ \ \ .fRbuttons.buttREFRESH\ \\\n\ \ \ -side\ left\ \\\n\ \ \ -anchor\ w\ \\\n\ \ \ -fill\ none\ \\\n\ \ \ -expand\ 0\n\n#\ \ \ \ \ .fRbuttons.labelSCALE\ \\\n#\ \ \ \ \ .fRbuttons.scaleSECONDS\ \\\n\n\n##+########################################################\n##\ In\ FRAME\ '.fRcanvases.fRcanvas1'\ -\n##\ DEFINE-and-PACK\ TWO\ LABELs\ and\n##\ ONE\ CANVAS\ WIDGET\ (no\ scrollbars).\n##\n##\ We\ highlightthickness\ &\ borderwidth\ of\ the\ canvas\ to\n##\ zero,\ as\ suggested\ on\ page\ 558,\ Chapter\ 37,\ 'The\ Canvas\n##\ Widget',\ in\ the\ 4th\ edition\ of\ the\ book\ 'Practical\n##\ Programming\ in\ Tcl\ and\ Tk'.\n##+#######################################################\n\nlabel\ .fRcanvases.fRcanvas1.labelINFO1\ \\\n\ \ \ -text\ \"\"\ \\\n\ \ \ -font\ fontTEMP_SMALL_varwidth\ \\\n\ \ \ -justify\ left\ \\\n\ \ \ -anchor\ w\ \\\n\ \ \ -relief\ flat\ \\\n\ \ \ -padx\ \$PADXpx_label\ \\\n\ \ \ -pady\ \$PADYpx_label\ \\\n\ \ \ -bd\ \$BDwidthPx_label\n\nlabel\ .fRcanvases.fRcanvas1.labelINFO2\ \\\n\ \ \ -text\ \"\"\ \\\n\ \ \ -font\ fontTEMP_SMALL_varwidth\ \\\n\ \ \ -justify\ left\ \\\n\ \ \ -anchor\ w\ \\\n\ \ \ -relief\ flat\ \\\n\ \ \ -padx\ \$PADXpx_label\ \\\n\ \ \ -pady\ \$PADYpx_label\ \\\n\ \ \ -bd\ \$BDwidthPx_label\n\ncanvas\ .fRcanvases.fRcanvas1.can\ \\\n\ \ \ -width\ \ \$initCanWidthPx\ \\\n\ \ \ -height\ \$initCanHeightPx\ \\\n\ \ \ -relief\ flat\ \\\n\ \ \ -highlightthickness\ 0\ \\\n\ \ \ -borderwidth\ 0\n\n##\ Pack\ the\ widgets\ in\ frame\ '.fRcanvases.fRcanvas1'.\n\npack\ .fRcanvases.fRcanvas1.labelINFO1\ \\\n\ \ \ \ \ .fRcanvases.fRcanvas1.labelINFO2\ \\\n\ \ \ -side\ top\ \\\n\ \ \ -anchor\ nw\ \\\n\ \ \ -fill\ x\ \\\n\ \ \ -expand\ 0\n\npack\ .fRcanvases.fRcanvas1.can\ \\\n\ \ \ -side\ top\ \\\n\ \ \ -anchor\ nw\ \\\n\ \ \ -fill\ none\ \\\n\ \ \ -expand\ 0\n\n\n##+########################################################\n##\ In\ FRAME\ '.fRcanvases.fRcanvas2'\ -\n##\ DEFINE-and-PACK\ TWO\ LABELs\ and\n##\ ONE\ CANVAS\ WIDGET\ (no\ scrollbars).\n##\n##\ We\ highlightthickness\ &\ borderwidth\ of\ the\ canvas\ to\n##\ zero,\ as\ suggested\ on\ page\ 558,\ Chapter\ 37,\ 'The\ Canvas\n##\ Widget',\ in\ the\ 4th\ edition\ of\ the\ book\ 'Practical\n##\ Programming\ in\ Tcl\ and\ Tk'.\n##+#######################################################\n\nlabel\ .fRcanvases.fRcanvas2.labelINFO1\ \\\n\ \ \ -text\ \"\"\ \\\n\ \ \ -font\ fontTEMP_SMALL_varwidth\ \\\n\ \ \ -justify\ left\ \\\n\ \ \ -anchor\ w\ \\\n\ \ \ -relief\ flat\ \\\n\ \ \ -padx\ \$PADXpx_label\ \\\n\ \ \ -pady\ \$PADYpx_label\ \\\n\ \ \ -bd\ \$BDwidthPx_label\n\nlabel\ .fRcanvases.fRcanvas2.labelINFO2\ \\\n\ \ \ -text\ \"\"\ \\\n\ \ \ -font\ fontTEMP_SMALL_varwidth\ \\\n\ \ \ -justify\ left\ \\\n\ \ \ -anchor\ w\ \\\n\ \ \ -relief\ flat\ \\\n\ \ \ -padx\ \$PADXpx_label\ \\\n\ \ \ -pady\ \$PADYpx_label\ \\\n\ \ \ -bd\ \$BDwidthPx_label\n\ncanvas\ .fRcanvases.fRcanvas2.can\ \\\n\ \ \ -width\ \ \$initCanWidthPx\ \\\n\ \ \ -height\ \$initCanHeightPx\ \\\n\ \ \ -relief\ flat\ \\\n\ \ \ -highlightthickness\ 0\ \\\n\ \ \ -borderwidth\ 0\n\n##\ Pack\ the\ widgets\ in\ frame\ '.fRcanvases.fRcanvas2'.\n\npack\ .fRcanvases.fRcanvas2.labelINFO1\ \\\n\ \ \ \ \ .fRcanvases.fRcanvas2.labelINFO2\ \\\n\ \ \ -side\ top\ \\\n\ \ \ -anchor\ nw\ \\\n\ \ \ -fill\ x\ \\\n\ \ \ -expand\ 0\n\npack\ .fRcanvases.fRcanvas2.can\ \\\n\ \ \ -side\ top\ \\\n\ \ \ -anchor\ nw\ \\\n\ \ \ -fill\ none\ \\\n\ \ \ -expand\ 0\n\n\n##+##################################################\n##\ END\ OF\ DEFINITION\ of\ the\ GUI\ widgets.\n##+##################################################\n##\ Start\ of\ BINDINGS,\ PROCS,\ Added-GUI-INIT\ sections.\n##+##################################################\n\n##+##################################################################\n##+##################################################################\n##\ \ BINDINGS\ SECTION:\ \ none\n##+##################################################################\n\n\n##+##################################################################\n##+##################################################################\n##\ DEFINE\ PROCS\ SECTION:\n##\n##\ \ \ \ 'make_tachometers'\ -\ to\ draw\ 2\ meters\ within\ 2\ Tk\ canvases\n##\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (We\ may\ allow\ the\ Tk\ canvases\ to\ resize\ according\ to\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ a\ resizing\ of\ the\ window.\ This\ proc\ will\ draw\ the\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 2\ meters\ in\ proportion\ to\ the\ size\ of\ their\ canvases.)\n##\n##\ \ \ \ 'make_one_tachometer'\ -\ to\ draw\ one\ tachometer.\ Called\ by\ 'make_tachometers'\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ to\ make\ the\ 2\ meters.\n##\n##\ \ \ \ 'draw_rivet'\ \ \ \ \ \ \ \ \ \ -\ called\ by\ 'make_tachometers'\ to\ put\ rivets\ in\ 4\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ corners\ around\ each\ meter.\n##\n##\ \ \ \ 'draw_circle_shadow'\ \ -\ called\ by\ 'make_tachometers'\ to\ put\ a\ shadowed\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ edge\ around\ the\ circle\ that\ makes\ each\ meter.\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Also\ called\ by\ 'make_tachometers'\ to\ put\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ a\ shadowed\ edge\ on\ the\ 'pin'\ that\ holds\ a\ needle.\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Also\ called\ by\ 'draw_rivet'\ to\ put\ a\ shadowed\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ edge\ on\ each\ rivet.\n##\n##\ \ \ \ 'update_needles'\ \ \ \ \ -\ to\ update\ the\ 2\ needles\ on\ the\ 2\ meters.\ Called\ in\ a\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ recursive\ loop,\ initiated\ at\ the\ bottom\ of\ this\ script.\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ And\ called\ in\ a\ 'Refresh'\ proc.\n##\n##\ \ \ 'update_one_needle'\ \ \ -\ to\ draw\ one\ needle\ in\ a\ specified\ canvas.\ Called\ by\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'update_needles'\ to\ update\ the\ 2\ needles\ on\ the\ 2\ meters.\n##\n##\ \ \ 'Refresh'\ \ \ \ \ \ \ \ \ \ \ \ \ -\ called\ by\ the\ 'Refresh'\ button.\ Runs\ the\ procs\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'make_tachometers'\ and\ 'update_needles'\ ---\ in\ particular,\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ the\ user\ to\ force\ the\ meters\ to\ be\ resized\ if\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ user\ resizes\ the\ window\ ---\ and\ whenever\ the\ user\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ wants\ a\ new\ 'reading'.\n##\n##\ 'popup_msgVarWithScroll'\ -\ to\ show\ the\ HELPtext\ var.\ Called\ by\ the\ 'Help'\ button.\n##\n##+#################################################################\n\n\n##+########################################################################\n##\ PROC\ 'make_tachometers'\n##+########################################################################\n##\ PURPOSE:\ Draws\ all\ features\ of\ 2\ tachometer-style\ meters\ (except\ the\n##\ \ \ \ \ \ \ \ \ \ needles)\ ---\ in\ a\ 'nice\ filling-size'\ according\ to\ the\n##\ \ \ \ \ \ \ \ \ \ current\ canvas\ dimensions.\n##\n##\ \ \ \ \ \ \ \ \ \ \ \ (We\ will\ allow\ the\ canvas\ to\ resize\ according\ to\n##\ \ \ \ \ \ \ \ \ \ \ \ \ a\ resizing\ of\ the\ window.\ This\ proc\ will\ redraw\ the\n##\ \ \ \ \ \ \ \ \ \ \ \ \ meters\ in\ proportion\ to\ the\ new\ size\ of\ the\ canvas.)\n##\n##\ CALLED\ BY:\ once,\ at\ the\ 'Additional\ GUI\ Initialization'\ section,\n##\ \ \ \ \ \ \ \ \ \ \ \ at\ the\ bottom\ of\ this\ script\ ---\ and\n##\ \ \ \ \ \ \ \ \ \ \ \ in\ the\ 'ReDraw...'\ proc.\n##+########################################################################\n\nproc\ make_tachometers\ \{\}\ \{\n\n\ \ \ global\ marginPx\n\n\ \ \ ##\ FOR\ TESTING:\ (to\ dummy\ out\ this\ proc)\n\ \ \ #\ \ return\n\n\ \ \ ############################################################\n\ \ \ ##\ Get\ current\ '.fRcanvases'\ dimensions\ ---\ in\ case\ the\ user\n\ \ \ ##\ has\ resized\ the\ window,\ and\ thus\ the\ '.fRcanvases'\ frame.\n\ \ \ ############################################################\n\ \n\ \ \ #\ set\ curCanvasesWidthPx\ \ \[.fRcanvases\ cget\ -width\]\n\ \ \ #\ set\ curCanvasesHeightPx\ \[.fRcanvases\ cget\ -height\]\n\n\ \ \ set\ curCanvasesWidthPx\ \ \[winfo\ width\ \ .fRcanvases\]\n\ \ \ set\ curCanvasesHeightPx\ \[winfo\ height\ .fRcanvases\]\n\n\n\ \ \ ############################################################\n\ \ \ ##\ Set\ a\ width-and-height\ to\ use\ for\ a\ canvas\n\ \ \ ##\ to\ contain\ each\ of\ the\ 2\ meters.\n\ \ \ ##\ (Half\ the\ 'fRcanvases'\ width.)\n\ \ \ ############################################################\n\n\ \ \ set\ canvasSizePx\ \[expr\ \{int((\$curCanvasesWidthPx\ -\ 8)\ /\ 2.0)\}\]\n\n\ \ \ if\ \{\$curCanvasesHeightPx\ <\ \$canvasSizePx\}\ \{set\ canvasSizePx\ \$curCanvasesHeightPx\}\n\n\ \ \ ####################################################################\n\ \ \ ##\ Resize\ the\ frames\ 'fRcanvas1'\ and\ 'fRcanvas2'\ that\n\ \ \ ##\ hold\ the\ 2\ (square)\ Tk\ canvases\ for\ the\ 2\ meters\n\ \ \ ##\ ---\ or\ resize\ the\ 2\ canvases,\ themselves.\n\ \ \ ####################################################################\n\n\ \ \ if\ \{0\}\ \{\n\ \ \ .fRcanvases.fRcanvas1\ configure\ -width\ \ \$canvasSizePx\n\ \ \ .fRcanvases.fRcanvas1\ configure\ -height\ \$canvasSizePx\n\ \ \ .fRcanvases.fRcanvas2\ configure\ -width\ \ \$canvasSizePx\n\ \ \ .fRcanvases.fRcanvas2\ configure\ -height\ \$canvasSizePx\n\ \ \ \}\n\n\ \ \ .fRcanvases.fRcanvas1.can\ configure\ -width\ \ \$canvasSizePx\n\ \ \ .fRcanvases.fRcanvas1.can\ configure\ -height\ \$canvasSizePx\n\ \ \ update\n\ \ \ .fRcanvases.fRcanvas2.can\ configure\ -width\ \ \$canvasSizePx\n\ \ \ .fRcanvases.fRcanvas2.can\ configure\ -height\ \$canvasSizePx\n\ \ \ update\n\n\ \ \ set\ doubleWidthPx\ \[expr\ \{(2\ *\ \$canvasSizePx)\ +\ 8\}\]\n\ \ \ .fRcanvases\ configure\ -width\ \ \$doubleWidthPx\n\ \ \ .fRcanvases\ configure\ -height\ \$canvasSizePx\n\ \ \ update\n\n\ \ \ #########################################################\n\ \ \ ##\ Draw\ meter1\ (without\ needle).\n\ \ \ #########################################################\n\n\ \ \ make_one_tachometer\ .fRcanvases.fRcanvas1.can\n\n\n\ \ \ #########################################################\n\ \ \ ##\ Draw\ meter2\ (without\ needle).\n\ \ \ #########################################################\n\n\ \ \ make_one_tachometer\ .fRcanvases.fRcanvas2.can\n\n\}\n##\ END\ OF\ proc\ 'make_tachometers'\n\n\n##+########################################################################\n##\ PROC\ 'make_one_tachometer'\n##+########################################################################\n##\ PURPOSE:\ Draws\ all\ features\ of\ a\ tachometer-style\ meter\ (except\ the\n##\ \ \ \ \ \ \ \ \ \ needle)\ ---\ according\ to\ the\ 'marginPx'\ parameter\ to\ set\n##\ \ \ \ \ \ \ \ \ \ top-right\ and\ bottom-left\ coordinates\ to\ specify\ the\ location\n##\ \ \ \ \ \ \ \ \ \ of\ the\ square\ exactly\ containing\ the\ circular\ meter\ on\n##\ \ \ \ \ \ \ \ \ \ the\ canvas\ whose\ ID\ is\ passed\ into\ this\ proc.\n##\n##\ \ The\ features\ include:\n##\ \ \ \ \ \ -\ white-filled\ circle\ for\ the\ meter\ background\n##\ \ \ \ \ \ -\ a\ gray-shaded\ (shadowed)\ edge\ around\ the\ circle\n##\ \ \ \ \ \ -\ a\ 'pin'\ in\ the\ center\ of\ the\ circle,\ for\ the\ needle\n##\ \ \ \ \ \ -\ 4\ decorative\ rivets\ at\ the\ corners\ of\ the\ canvas\n##\ \ \ \ \ \ -\ an\ arc\ with\ tic-marks\n##\ \ \ \ \ \ -\ a\ red\ danger-zone\ in\ the\ last\ segment\ of\ the\ arc\n##\ \ \ \ \ \ \ \ (between\ the\ last\ pair\ of\ tic-marks)\n##\ \ \ \ \ \ -\ labels\ for\ the\ tic-marks\n##\n##\ CALLED\ BY:\ proc\ 'make_tachometers'\n##+#######################################################################\n\n##\ Set\ an\ 'indentation'\ to\ use\ for\ placing\ the\ outer-circle\ of\ the\ 2\ meters\n##\ from\ the\ 4\ edges\ of\ their\ respective\ canvases.\n\nset\ marginPx\ 12\n\nset\ pi\ \[expr\ \{4.0\ *\ atan(1.0)\}\]\nset\ radsPERdeg\ \[expr\ \{\$pi/180.0\}\]\n\nset\ Nsegs\ 10\nset\ pcentLabels\ \"0\ 10\ 20\ 30\ 40\ 50\ 60\ 70\ 80\ 90\ 100\"\n\n##\ The\ above\ variables\ are\ set\ ONCE,\ for\ use\ in\ the\ following\ proc.\n\nproc\ make_one_tachometer\ \{canvas\}\ \{\n\n\ \ \ global\ marginPx\ pi\ radsPERdeg\ Nsegs\ pcentLabels\n\n\ \ \ ##\ FOR\ TESTING:\ (to\ dummy\ out\ this\ proc)\n\ \ \ #\ \ \ return\n\ \n\ \ \ ################################################################\n\ \ \ ##\ Remove\ any\ previously\ drawn\ elements\ in\ this\ canvas,\ if\ any.\n\ \ \ ################################################################\n\n\ \ \ catch\ \{\$canvas\ delete\ all\}\n\n\n\ \ \ ##################################################################\n\ \ \ ##\ Get\ the\ width\ (=\ height)\ of\ the\ specified\ (square)\ canvas.\n\ \ \ ##################################################################\n\n\ \ \ set\ curCanvasSizePx\ \ \[winfo\ width\ \ \$canvas\]\n\n\ \ \ ##################################################################\n\ \ \ ##\ Set\ the\ corner\ coords\ for\ drawing\ the\ meter\ circle\ (background).\n\ \ \ ##################################################################\n\n\ \ \ set\ topleftXpx\ \$marginPx\n\ \ \ set\ topleftYpx\ \$marginPx\n\ \ \ set\ botrightXpx\ \[expr\ \{\$curCanvasSizePx\ -\ \$marginPx\}\]\n\ \ \ set\ botrightYpx\ \[expr\ \{\$curCanvasSizePx\ -\ \$marginPx\}\]\n\n\n\ \ \ ################################################\n\ \ \ ##\ Draw\ basic\ white-filled\ circle\ for\ the\ meter.\n\ \ \ ################################################\n\n\ \ \ \$canvas\ create\ oval\ \\\n\ \ \ \ \ \ \$topleftXpx\ \$topleftYpx\ \$botrightXpx\ \$botrightYpx\ \\\n\ \ \ \ \ \ -fill\ white\ -outline\ \{\}\n\n\ \ \ #\ -width\ 1\ -outline\ lightgray\n\n\ \ \ ##\ FOR\ TESTING:\ (exit\ this\ proc\ before\ adding\ more\ to\ the\ meter)\n\ \ \ #\ \ \ return\n\n\n\ \ \ #######################################################################\n\ \ \ ##\ Draw\ shadow-circle\ at\ the\ outer\ circle\ of\ the\ meter.\n\ \ \ #######################################################################\n\ \ \ ##\ INPUTS:\n\ \ \ ##\ -\ the\ 4\ corner\ coordinates\ of\ the\ oval/circle\ box\ (in\ pixels)\n\ \ \ ##\ -\ number\ of\ segments\ for\ the\ arc\ (segments\ of\ differing\ color\ shade)\n\ \ \ ##\ -\ width\ (in\ pixels)\ to\ draw\ the\ arc\ segments\n\ \ \ ##\ -\ start\ angle\ for\ drawing\ the\ (darker)\ arc\ segments\n\ \ \ ##\ \ \ (measured\ counter-clockwise\ from\ the\ 3\ o'clock\ position)\n\ \ \ ##\ \ \ (An\ angle\ of\ +135=90+45\ means\ the\ dark\ side\ of\ the\ 'shadow-circle'\n\ \ \ ##\ \ \ \ is\ on\ the\ north-west\ side\ of\ the\ circle.)\n\ \ \ ######################################################################\n\n\ \ \ draw_circle_shadow\ \$canvas\ \\\n\ \ \ \ \ \ \$topleftXpx\ \$topleftYpx\ \$botrightXpx\ \$botrightYpx\ \\\n\ \ \ \ \ \ 40\ 6\ 135.0\n\ \n\ \ \ ##\ FOR\ TESTING:\ (exit\ this\ proc\ before\ adding\ more\ to\ the\ meter)\n\ \ \ #\ \ \ return\n\n\n\ \ \ ###################################################################\n\ \ \ ##\ Draw\ a\ shadow-circle\ for\ the\ 'pin'\ of\ the\ meter\ needle.\n\ \ \ ###################################################################\n\ \ \ ##\ INPUTS:\n\ \ \ ##\ -\ the\ 4\ corner\ coordinates\ of\ the\ oval/circle\ box\ (in\ pixels)\n\ \ \ ##\ -\ number\ of\ segments\ for\ the\ arc\ (segments\ of\ differing\ color\ shade)\n\ \ \ ##\ -\ width\ (in\ pixels)\ to\ draw\ the\ arc\ segments\n\ \ \ ##\ -\ start\ angle\ for\ drawing\ the\ (darker)\ arc\ segments\n\ \ \ ##\ \ \ \ (measured\ counter-clockwise\ from\ the\ 3\ o'clock\ position)\n\ \ \ ##\ \ \ \ (An\ angle\ of\ -45\ means\ the\ dark\ side\ of\ the\ 'shadow-circle'\n\ \ \ ##\ \ \ \ \ is\ on\ the\ south-east\ side\ of\ the\ circle.)\n\ \ \ ###################################################################\n\n\ \ \ set\ centerXpx\ \[expr\ \{int(\$curCanvasSizePx/2.0)\}\]\n\ \ \ set\ centerYpx\ \$centerXpx\n\n\ \ \ set\ pinOuterRadiusPx\ 14\n\n\ \ \ set\ x1\ \[expr\ \{\$centerXpx\ -\ \$pinOuterRadiusPx\}\]\n\ \ \ set\ y1\ \[expr\ \{\$centerYpx\ -\ \$pinOuterRadiusPx\}\]\n\ \ \ set\ x2\ \[expr\ \{\$centerXpx\ +\ \$pinOuterRadiusPx\}\]\n\ \ \ set\ y2\ \[expr\ \{\$centerYpx\ +\ \$pinOuterRadiusPx\}\]\n\n\ \ \ draw_circle_shadow\ \$canvas\ \$x1\ \$y1\ \$x2\ \$y2\ 40\ 6\ -45.0\n\n\ \ \ ##\ FOR\ TESTING:\ (exit\ this\ proc\ before\ adding\ more\ to\ the\ meter)\n\ \ \ #\ \ \ return\n\n\n\ \ \ ############################################################\n\ \ \ ##\ Draw\ a\ red-filled\ circle\ on\ the\ 'pin'\ of\ the\ meter\ needle.\n\ \ \ ############################################################\n\n\ \ \ set\ pinRadiusPx\ 12\n\n\ \ \ set\ x1\ \[expr\ \{\$centerXpx\ -\ \$pinRadiusPx\}\]\n\ \ \ set\ y1\ \[expr\ \{\$centerYpx\ -\ \$pinRadiusPx\}\]\n\ \ \ set\ x2\ \[expr\ \{\$centerXpx\ +\ \$pinRadiusPx\}\]\n\ \ \ set\ y2\ \[expr\ \{\$centerYpx\ +\ \$pinRadiusPx\}\]\n\n\ \ \ \$canvas\ create\ oval\ \\\n\ \ \ \ \ \ \$x1\ \$y1\ \$x2\ \$y2\ -fill\ red\ -outline\ \{\}\n\n\ \ \ #\ \ \ -width\ 1\ -outline\ lightgray\n\n\ \ \ ##\ FOR\ TESTING:\ (exit\ this\ proc\ before\ adding\ more\ to\ the\ meter)\n\ \ \ #\ \ \ return\n\n\n\ \ \ ###########################################\n\ \ \ ##\ Draw\ arc-line\ on\ which\ to\ put\ tic\ marks.\n\ \ \ #################################################\n\ \ \ ##\ 320\ degrees\ counter-clockwise\ from\ -70\ degrees\n\ \ \ ##\ (based\ at\ 3\ oclock)\ is\ 70\ degrees\ beyond\ 180.\n\ \ \ ##\ I.e.\ -70\ +\ 320\ =\ 250\ =\ 180\ +\ 70\n\ \ \ #################################################\n\n\ \ \ set\ arcLineIndentPx\ 10\n\n\ \ \ set\ x1\ \[expr\ \{\$topleftXpx\ \ +\ \$arcLineIndentPx\}\]\n\ \ \ set\ y1\ \[expr\ \{\$topleftYpx\ \ +\ \$arcLineIndentPx\}\]\n\ \ \ set\ x2\ \[expr\ \{\$botrightXpx\ -\ \$arcLineIndentPx\}\]\n\ \ \ set\ y2\ \[expr\ \{\$botrightYpx\ -\ \$arcLineIndentPx\}\]\n\n\ \ \ \$canvas\ create\ arc\ \$x1\ \$y1\ \$x2\ \$y2\ \\\n\ \ \ \ \ \ -start\ -70\ -extent\ 320\ -style\ arc\ \\\n\ \ \ \ \ \ -outline\ black\ -width\ 2\n\n\ \ \ ##\ FOR\ TESTING:\ (exit\ this\ proc\ before\ adding\ more\ to\ the\ meter)\n\ \ \ #\ \ \ return\n\n\n\ \ \ ##################################################\n\ \ \ ##\ Draw\ tic-marks\ and\ labels\ around\ the\ meter.\n\ \ \ ##################################################\n\n\ \ \ set\ DEGperTIC\ \[expr\ \{320.0/\$Nsegs\}\]\n\ \ \ set\ half\ \ \$centerXpx\n\n\ \ \ ##\ \ outer\ location\ (radius)\ of\ tic\ marks\n\ \ \ set\ l1\ \ \ \ \[expr\ \{\$half\ -\ (\$arcLineIndentPx\ +\ \$marginPx)\}\]\n\n\ \ \ ##\ \ inner\ location\ (radius)\ of\ tic\ marks\n\ \ \ set\ l2\ \ \ \ \[expr\ \{\$l1\ -\ \$arcLineIndentPx\}\]\n\n\ \ \ ##\ inner\ location\ of\ tic\ labels\n\ \ \ set\ l3\ \ \ \ \[expr\ \{\$l2\ -\ \$arcLineIndentPx\}\]\n\ \n\ \ \ set\ angle0\ \ 250.0\n\n\ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <=\ \$Nsegs\}\ \{incr\ i\}\ \{\n\n\ \ \ \ \ \ set\ rads\ \[expr\ \{(\$angle0\ -\ (\$DEGperTIC\ *\ \$i))\ *\ \$radsPERdeg\}\]\n\ \n\ \ \ \ \ \ set\ x1\ \[expr\ \{\$half\ +\ \$l1\ *\ cos(\$rads)\}\]\n\ \ \ \ \ \ set\ y1\ \[expr\ \{\$half\ -\ \$l1\ *\ sin(\$rads)\}\]\n\ \ \ \ \ \ set\ x2\ \[expr\ \{\$half\ +\ \$l2\ *\ cos(\$rads)\}\]\n\ \ \ \ \ \ set\ y2\ \[expr\ \{\$half\ -\ \$l2\ *\ sin(\$rads)\}\]\n\n\ \ \ \ \ \ \$canvas\ \ create\ line\ \\\n\ \ \ \ \ \ \ \ \ \$x1\ \$y1\ \$x2\ \$y2\ \\\n\ \ \ \ \ \ \ \ \ -fill\ black\ -width\ 2\n\ \n\ \ \ \ \ \ set\ x1\ \[expr\ \{\$half\ +\ \$l3\ *\ cos(\$rads)\}\]\n\ \ \ \ \ \ set\ y1\ \[expr\ \{\$half\ -\ \$l3\ *\ sin(\$rads)\}\]\n\ \n\ \ \ \ \ \ set\ label\ \[lindex\ \$pcentLabels\ \$i\]\n\n\ \ \ \ \ \ if\ \{\ \[string\ length\ \$label\]\ \}\ \{\n\ \ \ \ \ \ \ \ \ \$canvas\ create\ text\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$x1\ \$y1\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -anchor\ center\ -justify\ center\ -fill\ black\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -text\ \$label\ -font\ \{\ Helvetica\ 10\ \}\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ ##\ END\ OF\ labels\ loop.\n\n\ \ \ \}\n\ \ \ ##\ END\ OF\ i-loop\ for\ tic-marks\n\n\ \ \ ##\ FOR\ TESTING:\ (exit\ this\ proc\ before\ adding\ more\ to\ the\ meter)\n\ \ \ #\ \ \ return\n\n\n\ \ \ #######################################################\n\ \ \ ##\ Draw\ red-line\ arc-segment\ (danger\ zone)\ of\ the\ meter.\n\ \ \ #######################################################\n\n\ \ \ set\ redLineIndentPx\ 15\n\n\ \ \ set\ x1\ \[expr\ \{\$topleftXpx\ \ +\ \$redLineIndentPx\}\]\n\ \ \ set\ y1\ \[expr\ \{\$topleftYpx\ \ +\ \$redLineIndentPx\}\]\n\ \ \ set\ x2\ \[expr\ \{\$botrightXpx\ -\ \$redLineIndentPx\}\]\n\ \ \ set\ y2\ \[expr\ \{\$botrightYpx\ -\ \$redLineIndentPx\}\]\n\n\ \ \ \$canvas\ create\ arc\ \$x1\ \$y1\ \$x2\ \$y2\ \\\n\ \ \ \ \ \ -start\ -70\ -extent\ \$DEGperTIC\ -style\ arc\ \\\n\ \ \ \ \ \ -outline\ red\ -fill\ red\ -width\ 8\n\n\ \ \ ##\ FOR\ TESTING:\ (exit\ this\ proc\ before\ adding\ more\ to\ the\ meter)\n\ \ \ #\ \ \ return\n\n\n\ \ \ ##################################\n\ \ \ ##\ Draw\ 4\ rivets\ around\ the\ meter.\n\ \ \ ##################################\n\n\ \ \ set\ RIVETindentPx\ 10\n\ \ \ set\ RIVEToutdentPx\ \[expr\ \{\$curCanvasSizePx\ -\ \$RIVETindentPx\}\]\n\n\ \ \ ##\ upper-left\ rivet\n\ \ \ draw_rivet\ \$canvas\ \$RIVETindentPx\ \$RIVETindentPx\n\ \ \ ##\ upper-right\ rivet\n\ \ \ draw_rivet\ \$canvas\ \$RIVEToutdentPx\ \$RIVETindentPx\n\ \ \ ##\ lower-left\ rivet\n\ \ \ draw_rivet\ \$canvas\ \$RIVETindentPx\ \$RIVEToutdentPx\n\ \ \ ##\ lower-right\ rivet\n\ \ \ draw_rivet\ \$canvas\ \$RIVEToutdentPx\ \$RIVEToutdentPx\n\n\ \n\}\n##\ END\ OF\ proc\ 'make_tachometers'\n\n\n##+########################################################################\n##\ PROC\ 'draw_rivet'\n##+########################################################################\n##\ PURPOSE:\ Put\ a\ rivet\ at\ a\ specified\ center\ point.\n##\ \ \ \ \ \ \ \ \ \ The\ center\ point\ is\ specified\ in\ pixels,\ as\ a\ location\ on\n##\ \ \ \ \ \ \ \ \ \ the\ canvas\ of\ the\ GUI,\ relative\ to\ the\ upper\ left\ corner.\n##\n##\ \ \ \ \ \ \ \ \ \ (We\ pass\ the\ radius\ of\ the\ rivets\ in\ a\ global\ variable.)\n##\n##\ CALLED\ BY:\ the\ 'make_tachometer'\ proc\n##+########################################################################\n\nset\ rivetRadiusPx\ 4\n\nproc\ draw_rivet\ \{\ canvas\ centerXpx\ centerYpx\ \}\ \{\n\n\ \ \ global\ rivetRadiusPx\n\n\ \ \ ##\ FOR\ TESTING:\n\ \ \ #\ \ \ return\n\n\ \ \ ########################################################\n\ \ \ ##\ Draw\ a\ color\ shaded\ arc\ using\n\ \ \ ##\ -\ 5\ arc\ segments\ around\ each\ half\ of\ the\ circle/oval\n\ \ \ ##\ -\ 3\ pixels\ for\ width\ of\ the\ arc\ segments\n\ \ \ ##\ -\ -45\ degrees\ for\ the\ start\ angle\ (darkest\ shade)\n\ \ \ ########################################################\n\n\ \ \ draw_circle_shadow\ \$canvas\ \\\n\ \ \ \ \ \ \[expr\ \{\$centerXpx\ -\ \$rivetRadiusPx\}\]\ \\\n\ \ \ \ \ \ \[expr\ \{\$centerYpx\ -\ \$rivetRadiusPx\}\]\ \\\n\ \ \ \ \ \ \[expr\ \{\$centerXpx\ +\ \$rivetRadiusPx\}\]\ \\\n\ \ \ \ \ \ \[expr\ \{\$centerYpx\ +\ \$rivetRadiusPx\}\]\ \\\n\ \ \ \ \ \ 5\ 3\ -45.0\n\n\}\n##\ END\ OF\ proc\ 'draw_rivet'\n\n\n##+########################################################################\n##\ PROC\ 'draw_circle_shadow'\n##+########################################################################\n##\ PURPOSE:\ Puts\ a\ shadowed\ edge\ around\ an\ oval/circle\ in\ a\ specified\ 'box'.\n##\ \ \ \ \ \ \ \ \ \ \n##\ INPUTS:\ -\ the\ corner\ coordinates\ of\ the\ oval/circle\ box\ (in\ pixels)\n##\ \ \ \ \ \ \ \ \ -\ number\ of\ segments\ for\ the\ arc\ (segments\ of\ differing\ color\ shade)\n##\ \ \ \ \ \ \ \ \ -\ width\ (in\ pixels)\ to\ draw\ the\ arc\ segments\n##\ \ \ \ \ \ \ \ \ -\ start\ angle\ for\ drawing\ the\ arc\ segments\n##\n##\ CALLED\ BY:\ the\ 'make_tachometers'\ and\ 'draw_rivets'\ procs\n##+########################################################################\n\nproc\ draw_circle_shadow\ \{canvas\ x1\ y1\ x2\ y2\ Nsegs\ ARCwidthPx\ startDEGREES\ \}\ \{\n\n\ \ \ ##\ FOR\ TESTING:\ (dummy\ out\ this\ proc)\n\ \ \ #\ \ \ return\n\n\ \ \ set\ DEGperSHADE\ \[expr\ \{180.0/\$Nsegs\}\]\n\n\ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <=\ \$Nsegs\}\ \{incr\ i\}\ \{\n\n\ \ \ \ \ \ set\ a\ \[expr\ \{(\$startDEGREES\ +\ \$i\ *\ \$DEGperSHADE)\}\]\n\ \ \ \ \ \ set\ b\ \[expr\ \{(\$startDEGREES\ -\ \$i\ *\ \$DEGperSHADE)\}\]\n\ \n\ \ \ \ \ \ ##\ Make\ darker\ grays\ for\ greater\ angles.\n\ \ \ \ \ \ set\ color255\ \[expr\ \{40\ +\ \$i*(200/\$Nsegs)\}\]\n\ \ \ \ \ \ set\ hexcolor\ \[format\ \"#%x%x%x\"\ \$color255\ \$color255\ \$color255\]\n\ \n\ \ \ \ \ \ \$canvas\ create\ arc\ \\\n\ \ \ \ \ \ \ \ \ \$x1\ \$y1\ \$x2\ \$y2\ \\\n\ \ \ \ \ \ \ \ \ -start\ \$a\ -extent\ \$DEGperSHADE\ \\\n\ \ \ \ \ \ \ \ \ -style\ arc\ -outline\ \$hexcolor\ -width\ \$ARCwidthPx\n\n\ \ \ \ \ \ \$canvas\ create\ arc\ \\\n\ \ \ \ \ \ \ \ \ \$x1\ \$y1\ \$x2\ \$y2\ \\\n\ \ \ \ \ \ \ \ \ -start\ \$b\ -extent\ \$DEGperSHADE\ \\\n\ \ \ \ \ \ \ \ \ -style\ arc\ -outline\ \$hexcolor\ -width\ \$ARCwidthPx\n\n\ \ \ \ \ \ ##\ FOR\ TESTING:\ \ (show\ each\ pair\ of\ segments\ before\n\ \ \ \ \ \ ##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ drawing\ the\ next\ pair)\n\ \ \ \ \ \ #\ update\n\n\ \ \ \}\n\ \ \ ##\ END\ OF\ loop\ over\ the\ arc\ segments\n\n\}\n##\ END\ OF\ proc\ 'draw_circle_shadow'\n\n\n\n##+########################################################################\n##\ PROC\ 'update_needles'\n##+########################################################################\n##\ PURPOSE:\ Updates\ the\ a\ needle\ on\ a\ square\ canvas\ ---\ using\ the\n##\ \ \ \ \ \ \ \ \ \ Linux/Unix/BSD/Mac\ 'free'\ command\ to\ get\ \n##\ \ \ \ \ \ \ \ \ \ MEMtot,\ MEMused,\ SWAPtot,\ SWAPused\ (in\ Megabytes).\n##\n##\ \ \ \ \ \ \ \ \ \ Input\ is\ the\ canvas\ ID.\ This\ proc\ queries\ the\ canvas\ to\n##\ \ \ \ \ \ \ \ \ \ get\ its\ center\ and\ to\ determine\ an\ appropriate\ length\ for\n##\ \ \ \ \ \ \ \ \ \ the\ needle.\n##\n##\ CALLED\ BY:\ the\ 'Additional\ GUI\ Initialization'\ section\ at\ the\n##\ \ \ \ \ \ \ \ \ \ \ \ bottom\ of\ this\ script,\ in\ a\ 'while'\ loop.\n##+########################################################################\n\ \nproc\ update_needles\ \{\}\ \{\n\n\ \ \ global\ argv0\n\ \ \ #\ global\ env\n\n\ \ \ ##########################################################\n\ \ \ ##\ Get\ the\ directory\ that\ this\ Tk\ script\ is\ in.\ That\ should\n\ \ \ ##\ be\ the\ directory\ that\ the\ utility\ shell\ script\ is\ in\n\ \ \ ##\ ---\ to\ get\ the\ memory\ and\ swap\ data\ values.\n\ \ \ ##########################################################\n\n\ \ \ ##\ FOR\ TESTING:\n\ \ \ #\ \ puts\ \"argv0:\ \$argv0\"\n\n\ \ \ #\ set\ thisDIR\ \".\"\n\ \ \ #\ set\ thisDIR\ \"\[pwd\]\"\n\ \ \ #\ set\ thisDIR\ \"\$env(HOME)/apps/tkUtils\"\n\ \ \ \ \ set\ thisDIR\ \"\[file\ dirname\ \$argv0\]\"\n\n\ \ \ ##########################################################\n\ \ \ ##\ Get\ MEMtot,MEMused,SWAPtot,SWAPused\ via\ 'free'\ command.\n\ \ \ ##########################################################\n\n\ \ \ foreach\ \{MEMtot\ MEMused\ SWAPtot\ SWAPused\}\ \\\n\ \ \ \ \ \ \[exec\ \$thisDIR/get_memory_and_swap.sh\]\ \{break\}\n\n\ \ \ ##\ FOR\ TESTING:\n\ \ \ #\ \ \ puts\ \"\ MEMtot:\ \$MEMtot\ \ \ \ \ \ MEMused:\ \$MEMused\"\n\ \ \ #\ \ \ puts\ \"SWAPtot:\ \$SWAPtot\ \ \ \ SWAPused:\ \$SWAPused\"\n\n\ \ \ #########################################################\n\ \ \ ##\ Update\ the\ 2\ needles.\n\ \ \ #########################################################\n\n\ \ \ ##\ FOR\ TESTING:\ (hardcoded\ meter\ values)\n\ \ \ #\ update_one_needle\ .fRcanvases.fRcanvas1\ 2000\ 650\ Memory\n\ \ \ #\ update_one_needle\ .fRcanvases.fRcanvas2\ 1000\ 0\ Swap\n\n\ \ \ update_one_needle\ .fRcanvases.fRcanvas1\ \$MEMtot\ \$MEMused\ Memory\n\n\ \ \ update_one_needle\ .fRcanvases.fRcanvas2\ \$SWAPtot\ \$SWAPused\ Swap\n\n\ \ \ ############################################################\n\ \ \ ##\ Force\ the\ needles\ to\ show\ up\ on\ the\ GUI.\ (???)\n\ \ \ ##\ (This\ may\ be\ needed\ because\ this\ proc\ is\ being\ called\n\ \ \ ##\ \ in\ a\ 'while'\ loop\ at\ the\ bottom\ of\ this\ script.\ We\n\ \ \ ##\ \ do\ not\ 'fall\ into'\ the\ normal\ Tk\ event\ handling\ loop.)\n\ \ \ ############################################################\n\n\ \ \ update\n\n\}\n##\ END\ OF\ proc\ 'update_needles'\n\n\n##+########################################################################\n##\ PROC\ 'update_one_needle'\n##+########################################################################\n##\ PURPOSE:\ Updates\ the\ a\ needle\ on\ a\ square\ canvas\ ---\ using\ the\n##\ \ \ \ \ \ \ \ \ \ canvas\ ID\ and\ the\ tot\ and\ used\ numbers\ passed\ as\ arguments.\n##\n##\ \ \ \ \ \ \ \ \ \ Input\ is\ the\ canvas\ ID.\ This\ proc\ queries\ the\ canvas\ to\n##\ \ \ \ \ \ \ \ \ \ get\ its\ center\ and\ to\ determine\ an\ appropriate\ length\ for\n##\ \ \ \ \ \ \ \ \ \ the\ needle\ as\ a\ proportion\ of\ the\ (square)\ canvas\ size.\n##\n##\ CALLED\ BY:\ the\ 'Additional\ GUI\ Initialization'\ section\ at\ the\n##\ \ \ \ \ \ \ \ \ \ \ \ bottom\ of\ this\ script,\ in\ a\ 'while'\ loop.\n##+########################################################################\n\ \nproc\ update_one_needle\ \{frame\ TOT\ USED\ TYPE\}\ \{\n\n\ \ \ global\ pi\ radsPERdeg\ Nsegs\n\n\ \ \ ##\ FOR\ TESTING:\ (dummy\ out\ this\ routine)\n\ \ \ #\ \ return\n\n\ \ \ set\ PERcent\ \ \[expr\ \{(\$USED\ \ *\ 100.0)\ /\ \ \$TOT\}\]\n\n\ \ \ set\ TOTtext\ \"Total\ \$TYPE\ =\ \$TOT\ Megabytes\"\n\ \ \ set\ USEDtext\ \"Used\ \$TYPE\ =\ \$USED\ Megabytes\"\n\n\ \ \ \$frame.labelINFO1\ configure\ -text\ \"\$TOTtext\"\n\ \ \ \$frame.labelINFO2\ configure\ -text\ \"\$USEDtext\"\n\n\ \ \ ##\ Set\ the\ angle\ for\ the\ zero-point\ on\ the\ arc-of-tic-marks.\n\n\ \ \ set\ angle0\ \ 250.0\n\n\ \ \ ##\ Convert\ PERcent\ to\ an\ angle\ in\ radians\ on\ the\ arc.\n\n\ \ \ set\ degs\ \[expr\ \{\$angle0\ -\ (320.0\ *\ \$PERcent\ /\ 100.0)\}\]\n\ \ \ set\ rads\ \[expr\ \{\$degs\ *\ \$radsPERdeg\}\]\n\n\ \ \ ##\ FOR\ TESTING:\n\ \ \ #\ \ \ puts\ \"PERcent:\ \$PERcent\ \ \ degs:\ \$degs\ \ rads:\ \$rads\"\n\n\ \ \ ##\ Get\ the\ coord(s)\ of\ the\ center\ of\ the\ (square)\ canvas\n\ \ \ ##\ and\ calculate\ a\ length\ of\ the\ needle.\n\n\ \ \ #\ set\ width\ \ \[\$frame.can\ cget\ -width\]\n\ \ \ set\ width\ \ \[winfo\ width\ \$frame.can\]\n\ \ \ set\ half\ \ \ \[expr\ \{int(\$width\ /\ 2.0)\}\]\n\ \ \ set\ length\ \[expr\ \{int(\$half\ *\ 0.5)\}\]\n\n\ \ \ ##\ Calculate\ the\ coordinates\ for\ the\ tip\ and\ base\ of\ the\ needle.\n\ \n\ \ \ set\ xtip\ \[expr\ \{\$half\ +\ \$length*cos(\$rads)\}\]\n\ \ \ set\ ytip\ \[expr\ \{\$half\ -\ \$length*sin(\$rads)\}\]\n\ \n\ \ \ #\ set\ xbase\ \[expr\ \{\$half\ +\ 0.2*\$length*cos(\$rads)\}\]\n\ \ \ #\ set\ ybase\ \[expr\ \{\$half\ -\ 0.2*\$length*sin(\$rads)\}\]\n\n\ \ \ set\ xbase\ \$half\n\ \ \ set\ ybase\ \$half\n\ \n\ \ \ ##\ Remove\ a\ previous\ needle,\ if\ any.\n\n\ \ \ catch\ \{\$frame.can\ delete\ -tags\ TAGneedle\}\n\n\ \ \ ##\ Draw\ a\ red-line\ needle\ and\ a\ reddish-white\ line\ on\ either\ side\n\ \ \ ##\ ---\ for\ an\ (attempted)\ anti-aliasing\ effect.\n\n\ \ \ \$frame.can\ create\ line\ \\\n\ \ \ \ \ \ \$xbase\ \$ybase\ \$xtip\ \$ytip\ \\\n\ \ \ \ \ \ -fill\ #ff0000\ -width\ 4\ -tag\ TAGneedle\n\n\ \ \ \$frame.can\ create\ line\ \\\n\ \ \ \ \ \ \[expr\ \{\$xbase\ +\ 1\}\]\ \[expr\ \{\$ybase\ +\ 1\}\]\ \\\n\ \ \ \ \ \ \[expr\ \{\$xtip\ +\ 1\}\]\ \ \[expr\ \{\$ytip\ +\ 1\}\]\ \\\n\ \ \ \ \ \ -fill\ #ff8888\ -width\ 2\ -tag\ TAGneedle\n\n\ \ \ \$frame.can\ create\ line\ \\\n\ \ \ \ \ \ \[expr\ \{\$xbase\ -\ 1\}\]\ \[expr\ \{\$ybase\ -\ 1\}\]\ \\\n\ \ \ \ \ \ \[expr\ \{\$xtip\ -\ 1\}\]\ \ \[expr\ \{\$ytip\ -\ 1\}\]\ \\\n\ \ \ \ \ \ -fill\ #ff8888\ -width\ 2\ -tag\ TAGneedle\n\n\}\n##\ END\ OF\ proc\ 'update_one_needle'\n\n\n\n##+#############################################################\n##\ proc\ Refresh\n##\n##\ PURPOSE:\ 'Refresh'\ the\ two\ meters\ and\ their\ needles\ ---\n##\ \ \ \ \ \ \ \ \ \ \ for\ when\ the\ user\ wants\ a\ new\ set\ of\ values\n##\ \ \ \ \ \ \ \ \ \ \ and/or\ when\ the\ user\ resizes\ the\ window.\n##\n##\ CALLED\ BY:\ 'Refresh'\ button\n##+#############################################################\n\nproc\ Refresh\ \{\}\ \{\n\n\ \ \ make_tachometers\n\ \ \ update_needles\n\n\}\n##\ END\ OF\ proc\ 'Refresh'\n\n\n##+#############################################################\n##\ proc\ ReDraw_if_canvases_resized\n##\n##\ PURPOSE:\ To\ handle\ resizing\ the\ meters\ when\ the\ window\ is\n##\ \ \ \ \ \ \ \ \ \ resized\ ---\ IF\ the\ <Configure>\ binding\ is\ implemented.\n##\n##\ \ \ \ \ \ \ \ \ \ The\ intent\ is\ to\ avoid\ too\ many\ redraws\ ---\ for\n##\ \ \ \ \ \ \ \ \ \ almost\ every\ little\ resize\ of\ the\ window\ as\ its\n##\ \ \ \ \ \ \ \ \ \ border(s)\ are\ dragged.\n##\n##\ CALLED\ BY:\ bind\ .fRcanvas.can\ <Configure>\ \n##\ \ \ \ \ \ \ \ \ \ \ \ at\ bottom\ of\ this\ script.\n##+#############################################################\n##\ NOT\ IMPLEMENTED.\n##\ Code\ is\ included\ for\ possible\ future\ development.\n##+#############################################################\n\nproc\ ReDraw_if_canvases_resized\ \{\}\ \{\n\n\ \ \ global\ \ PREVcanvasesWidthPx\ PREVcanvasesHeightPx\ draw_wait0or1\n\n\ \ \ ##\ FOR\ TESTING:\ (to\ dummy\ out\ this\ proc)\n\ \ \ #\ \ return\n\n\ \ \ if\ \{\$draw_wait0or1\ ==\ 1\}\ \{return\}\n\n\ \ \ ##\ Set\ the\ wait\ indicator\ and\ delay\ doing\ the\ canvas\ resize\n\ \ \ ##\ check\ for\ about\ 300\ milliseconds\ ---\ to\ allow\ time\ for\ the\n\ \ \ ##\ user\ to\ stop\ moving\ the\ window.\ After\ about\ 300\ milliseconds,\n\ \ \ ##\ it\ is\ unlikely\ that\ the\ window\ is\ moving\ and\ thus\ causing\n\ \ \ ##\ multiple\ redraws.\n\n\ \ \ set\ draw_wait0or1\ 1\n\ \ \ after\ 900\n\n\ \ \ set\ CURcanvasesWidthPx\ \ \[winfo\ width\ \ .fRcanvases\]\n\ \ \ set\ CURcanvasesHeightPx\ \[winfo\ height\ .fRcanvases\]\n\n\ \ \ if\ \{\ \$CURcanvasesWidthPx\ \ !=\ \$PREVcanvasesWidthPx\ ||\ \\\n\ \ \ \ \ \ \ \ \$CURcanvasesHeightPx\ !=\ \$PREVcanvasesHeightPx\}\ \{\n\n\ \ \ \ \ \ make_tachometers\n\ \ \ \ \ \ update_needles\n\n\ \ \ \ \ \ set\ PREVcanvasesWidthPx\ \ \$CURcanvasesWidthPx\n\ \ \ \ \ \ set\ PREVcanvasesHeightPx\ \$CURcanvasesHeightPx\n\ \ \ \ \ \ set\ draw_wait0or1\ 0\n\ \ \ \}\n\n\}\n##\ END\ OF\ proc\ 'ReDraw_if_canvases_resized'\n\n\n##+########################################################################\n##\ PROC\ 'popup_msgVarWithScroll'\n##+########################################################################\n##\ PURPOSE:\ Report\ help\ or\ error\ conditions\ to\ the\ user.\n##\n##\ \ \ \ \ \ \ We\ do\ not\ use\ focus,grab,tkwait\ in\ this\ proc,\n##\ \ \ \ \ \ \ because\ we\ use\ it\ to\ show\ help\ when\ the\ GUI\ is\ idle,\n##\ \ \ \ \ \ \ and\ we\ may\ want\ the\ user\ to\ be\ able\ to\ keep\ the\ Help\n##\ \ \ \ \ \ \ window\ open\ while\ doing\ some\ other\ things\ with\ the\ GUI\n##\ \ \ \ \ \ \ such\ as\ putting\ a\ filename\ in\ the\ filename\ entry\ field\n##\ \ \ \ \ \ \ or\ clicking\ on\ a\ radiobutton.\n##\n##\ \ \ \ \ \ \ For\ a\ similar\ proc\ with\ focus-grab-tkwait\ added,\n##\ \ \ \ \ \ \ see\ the\ proc\ 'popup_msgVarWithScroll_wait'\ in\ a\n##\ \ \ \ \ \ \ 3DterrainGeneratorExaminer\ Tk\ script.\n##\n##\ REFERENCE:\ page\ 602\ of\ 'Practical\ Programming\ in\ Tcl\ and\ Tk',\n##\ \ \ \ \ \ \ \ \ \ \ \ 4th\ edition,\ by\ Welch,\ Jones,\ Hobbs.\n##\n##\ ARGUMENTS:\ A\ toplevel\ frame\ name\ (such\ as\ .fRhelp\ or\ .fRerrmsg)\n##\ \ \ \ \ \ \ \ \ \ \ \ and\ a\ variable\ holding\ text\ (many\ lines,\ if\ needed).\n##\n##\ CALLED\ BY:\ 'help'\ button\n##+########################################################################\n##\ To\ have\ more\ control\ over\ the\ formatting\ of\ the\ message\ (esp.\n##\ words\ per\ line),\ we\ use\ this\ 'toplevel-text'\ method,\ \n##\ rather\ than\ the\ 'tk_dialog'\ method\ --\ like\ on\ page\ 574\ of\ the\ book\ \n##\ by\ Hattie\ Schroeder\ &\ Mike\ Doyel,'Interactive\ Web\ Applications\n##\ with\ Tcl/Tk',\ Appendix\ A\ \"ED,\ the\ Tcl\ Code\ Editor\".\n##+########################################################################\n\nproc\ popup_msgVarWithScroll\ \{\ toplevName\ VARtext\ \}\ \{\n\n\ \ \ ##\ global\ fontTEMP_varwidth\ #\;\ Not\ needed.\ 'wish'\ makes\ this\ global.\n\ \ \ ##\ global\ env\n\n\ \ \ #\ bell\n\ \ \ #\ bell\n\ \ \n\ \ \ #################################################\n\ \ \ ##\ Set\ VARwidth\ &\ VARheight\ from\ \$VARtext.\n\ \ \ #################################################\n\ \ \ ##\ To\ get\ VARheight,\n\ \ \ ##\ \ \ \ split\ at\ '\\n'\ (newlines)\ and\ count\ 'lines'.\n\ \ \ #################################################\n\ \n\ \ \ set\ VARlist\ \[\ split\ \$VARtext\ \"\\n\"\ \]\n\n\ \ \ ##\ For\ testing:\n\ \ \ #\ \ puts\ \"VARlist:\ \$VARlist\"\n\n\ \ \ set\ VARheight\ \[\ llength\ \$VARlist\ \]\n\n\ \ \ ##\ For\ testing:\n\ \ \ #\ \ puts\ \"VARheight:\ \$VARheight\"\n\n\n\ \ \ #################################################\n\ \ \ ##\ To\ get\ VARwidth,\n\ \ \ ##\ \ \ \ loop\ through\ the\ 'lines'\ getting\ length\n\ \ \ ##\ \ \ \ \ of\ each\;\ save\ max.\n\ \ \ #################################################\n\n\ \ \ set\ VARwidth\ 0\n\n\ \ \ #############################################\n\ \ \ ##\ LOOK\ AT\ EACH\ LINE\ IN\ THE\ LIST.\n\ \ \ #############################################\n\ \ \ foreach\ line\ \$VARlist\ \{\n\n\ \ \ \ \ \ #############################################\n\ \ \ \ \ \ ##\ Get\ the\ length\ of\ the\ line.\n\ \ \ \ \ \ #############################################\n\ \ \ \ \ \ set\ LINEwidth\ \[\ string\ length\ \$line\ \]\n\n\ \ \ \ \ \ if\ \{\ \$LINEwidth\ >\ \$VARwidth\ \}\ \{\n\ \ \ \ \ \ \ \ \ set\ VARwidth\ \$LINEwidth\ \n\ \ \ \ \ \ \}\n\n\ \ \ \}\n\ \ \ ##\ END\ OF\ foreach\ line\ \$VARlist\n\n\ \ \ ##\ For\ testing:\n\ \ \ #\ \ \ puts\ \"VARwidth:\ \$VARwidth\"\n\n\n\ \ \ ###############################################################\n\ \ \ ##\ NOTE:\ VARwidth\ works\ for\ a\ fixed-width\ font\ used\ for\ the\n\ \ \ ##\ \ \ \ \ \ \ text\ widget\ ...\ BUT\ the\ programmer\ may\ need\ to\ be\n\ \ \ ##\ \ \ \ \ \ \ careful\ that\ the\ contents\ of\ VARtext\ are\ all\n\ \ \ ##\ \ \ \ \ \ \ countable\ characters\ by\ the\ 'string\ length'\ command.\n\ \ \ ###############################################################\n\n\n\ \ \ #####################################\n\ \ \ ##\ SETUP\ 'TOP\ LEVEL'\ HELP\ WINDOW.\n\ \ \ #####################################\n\n\ \ \ catch\ \{destroy\ \$toplevName\}\n\ \ \ toplevel\ \ \$toplevName\n\n\ \ \ #\ wm\ geometry\ \$toplevName\ 600x400+100+50\n\n\ \ \ wm\ geometry\ \$toplevName\ +100+50\n\n\ \ \ wm\ title\ \ \ \ \ \$toplevName\ \"Note\"\n\ \ \ #\ wm\ title\ \ \ \$toplevName\ \"Note\ to\ \$env(USER)\"\n\n\ \ \ wm\ iconname\ \ \$toplevName\ \"Note\"\n\n\n\ \ \ #####################################\n\ \ \ ##\ In\ the\ frame\ '\$toplevName'\ -\n\ \ \ ##\ DEFINE\ THE\ TEXT\ WIDGET\ and\n\ \ \ ##\ its\ two\ scrollbars\ ---\ and\n\ \ \ ##\ DEFINE\ an\ OK\ BUTTON\ widget.\n\ \ \ #####################################\n\n\ \ \ if\ \{\$VARheight\ >\ 10\}\ \{\n\ \ \ \ \ \ text\ \$toplevName.text\ \\\n\ \ \ \ \ \ \ \ \ -wrap\ none\ \\\n\ \ \ \ \ \ \ \ \ -font\ fontTEMP_varwidth\ \\\n\ \ \ \ \ \ \ \ \ -width\ \ \$VARwidth\ \\\n\ \ \ \ \ \ \ \ \ -height\ \$VARheight\ \\\n\ \ \ \ \ \ \ \ \ -bg\ \"#f0f0f0\"\ \\\n\ \ \ \ \ \ \ \ \ -relief\ raised\ \\\n\ \ \ \ \ \ \ \ \ -bd\ 2\ \\\n\ \ \ \ \ \ \ \ \ -yscrollcommand\ \"\$toplevName.scrolly\ set\"\ \\\n\ \ \ \ \ \ \ \ \ -xscrollcommand\ \"\$toplevName.scrollx\ set\"\n\n\ \ \ \ \ \ scrollbar\ \$toplevName.scrolly\ \\\n\ \ \ \ \ \ \ \ \ -orient\ vertical\ \\\n\ \ \ \ \ \ \ \ \ -command\ \"\$toplevName.text\ yview\"\n\n\ \ \ \ \ \ scrollbar\ \$toplevName.scrollx\ \\\n\ \ \ \ \ \ \ \ \ -orient\ horizontal\ \\\n\ \ \ \ \ \ \ \ \ -command\ \"\$toplevName.text\ xview\"\n\ \ \ \}\ else\ \{\n\ \ \ \ \ \ text\ \$toplevName.text\ \\\n\ \ \ \ \ \ \ \ \ -wrap\ none\ \\\n\ \ \ \ \ \ \ \ \ -font\ fontTEMP_varwidth\ \\\n\ \ \ \ \ \ \ \ \ -width\ \ \$VARwidth\ \\\n\ \ \ \ \ \ \ \ \ -height\ \$VARheight\ \\\n\ \ \ \ \ \ \ \ \ -bg\ \"#f0f0f0\"\ \\\n\ \ \ \ \ \ \ \ \ -relief\ raised\ \\\n\ \ \ \ \ \ \ \ \ -bd\ 2\ \n\ \ \ \}\n\n\ \ \ button\ \$toplevName.butt\ \\\n\ \ \ \ \ \ -text\ \"OK\"\ \\\n\ \ \ \ \ \ -font\ fontTEMP_varwidth\ \\\n\ \ \ \ \ \ -command\ \ \"destroy\ \$toplevName\"\n\n\ \ \ ###############################################\n\ \ \ ##\ PACK\ *ALL*\ the\ widgets\ in\ frame\ '\$toplevName'.\n\ \ \ ###############################################\n\n\ \ \ ##\ Pack\ the\ bottom\ button\ BEFORE\ the\n\ \ \ ##\ bottom\ x-scrollbar\ widget,\n\n\ \ \ pack\ \ \$toplevName.butt\ \\\n\ \ \ \ \ \ -side\ bottom\ \\\n\ \ \ \ \ \ -anchor\ center\ \\\n\ \ \ \ \ \ -fill\ none\ \\\n\ \ \ \ \ \ -expand\ 0\n\n\n\ \ \ if\ \{\$VARheight\ >\ 10\}\ \{\n\ \ \ \ \ \ ##\ Pack\ the\ scrollbars\ BEFORE\ the\ text\ widget,\n\ \ \ \ \ \ ##\ so\ that\ the\ text\ does\ not\ monopolize\ the\ space.\n\n\ \ \ \ \ \ pack\ \$toplevName.scrolly\ \\\n\ \ \ \ \ \ \ \ \ -side\ right\ \\\n\ \ \ \ \ \ \ \ \ -anchor\ center\ \\\n\ \ \ \ \ \ \ \ \ -fill\ y\ \\\n\ \ \ \ \ \ \ \ \ -expand\ 0\n\n\ \ \ \ \ \ ##\ DO\ NOT\ USE\ '-expand\ 1'\ HERE\ on\ the\ Y-scrollbar.\n\ \ \ \ \ \ ##\ THAT\ ALLOWS\ Y-SCROLLBAR\ TO\ EXPAND\ AND\ PUTS\n\ \ \ \ \ \ ##\ BLANK\ SPACE\ BETWEEN\ Y-SCROLLBAR\ &\ THE\ TEXT\ AREA.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ pack\ \$toplevName.scrollx\ \\\n\ \ \ \ \ \ \ \ \ -side\ bottom\ \\\n\ \ \ \ \ \ \ \ \ -anchor\ center\ \\\n\ \ \ \ \ \ \ \ \ -fill\ x\ \ \\\n\ \ \ \ \ \ \ \ \ -expand\ 0\n\n\ \ \ \ \ \ ##\ DO\ NOT\ USE\ '-expand\ 1'\ HERE\ on\ the\ X-scrollbar.\n\ \ \ \ \ \ ##\ THAT\ KEEPS\ THE\ TEXT\ AREA\ FROM\ EXPANDING.\n\n\ \ \ \ \ \ pack\ \$toplevName.text\ \\\n\ \ \ \ \ \ \ \ \ -side\ top\ \\\n\ \ \ \ \ \ \ \ \ -anchor\ center\ \\\n\ \ \ \ \ \ \ \ \ -fill\ both\ \\\n\ \ \ \ \ \ \ \ \ -expand\ 1\n\ \ \ \}\ else\ \{\n\ \ \ \ \ \ pack\ \$toplevName.text\ \\\n\ \ \ \ \ \ \ \ \ -side\ top\ \\\n\ \ \ \ \ \ \ \ \ -anchor\ center\ \\\n\ \ \ \ \ \ \ \ \ -fill\ both\ \\\n\ \ \ \ \ \ \ \ \ -expand\ 1\n\ \ \ \}\n\n\n\ \ \ #####################################\n\ \ \ ##\ LOAD\ MSG\ INTO\ TEXT\ WIDGET.\n\ \ \ #####################################\n\n\ \ \ ##\ \ \$toplevName.text\ delete\ 1.0\ end\n\ \n\ \ \ \$toplevName.text\ insert\ end\ \$VARtext\n\ \ \ \n\ \ \ \$toplevName.text\ configure\ -state\ disabled\n\ \ \n\}\n##\ END\ OF\ PROC\ 'popup_msgVarWithScroll'\n\n\n##+########################\n##\ END\ of\ PROC\ definitions.\n##+########################\n##\ Set\ HELPtext\ var.\n##+########################\n\n\nset\ HELPtext\ \"\\\n\\\ \\\ **\ HELP\ for\ this\ 'Memory\ and\ Swap\ Usage'\ Monitoring\ Utility\ **\n\nThis\ utility\ is\ meant\ to\ show\ a\ GUI\ that\ holds\ a\ pair\ of\ntachometer-style\ meters.\ The\ needles\ on\ the\ meters\ are\ updated\nperiodically\ ---\ whenever\ the\ user\ chooses\ to\ click\ on\ the\n'Refresh'\ button\ ---\ to\ show\ the\ PERCENT\ of\ available\nMEMORY\ and\ SWAP\ resources\ in\ use,\ on\ this\ computer\ ---\nas\ well\ as\ the\ actual\ TOTAL\ and\ USED\ values\ of\ the\ those\ntwo\ resources.\n\nThis\ Tcl-Tk\ script\ was\ developed\ on\ Linux\ and\ uses\ the\ 'free'\ncommand\ to\ get\ the\ memory\ and\ swap\ data\ to\ determine\ where\ to\nrelocate\ the\ position\ of\ the\ needles\ on\ the\ meters.\n\nThere\ are\ a\ couple\ of\ Tk\ 'canvas'\ widgets\ that\ contain\ two\ meter\ images\n---\ one\ for\ percent-memory-in-use\ and\ one\ for\ percent-swap-in-use.\n\n\n***************************************\nWINDOW\ RESIZE\ (an\ experimental\ feature):\n\nWe\ can\ allow\ the\ user\ to\ resize\ the\ window\ rather\ than\ using\ a\ fixed\nwindow\ (and\ fixed\ meters)\ size.\ If\ the\ user\ resizes\ the\ window,\ the\n'Refresh'\ button\ can\ be\ used\ to\ force\ the\ meters\ to\ be\ resized\naccording\ to\ the\ new\ window\ size.\ (The\ meters\ may\ be\ resized\ such\ that\nthey\ are\ 'too\ tall'\ for\ the\ new\ window\ size.\ Just\ pull\ the\ window\ down,\nto\ see\ the\ entire\ meters.)\n\n************************************\nTHE\ SCRIPT\ USED\ to\ update\ the\ meters:\n\nA\ Tcl\ 'exec'\ command\ calls\ on\ a\ separate\ shell\ script\ ---\n'get_memory_and_swap.sh'\ ---\ that\ uses\ the\ 'free'\ command\nto\ get\ the\ memory\ and\ swap\ data\ (total\ and\ used)\ and\nextract-and-format\ the\ data\ for\ return\ to\ this\ Tk\ script.\n\nIf\ the\ 'free'\ command\ is\ not\ available\ on\ your\ computer,\nyou\ may\ have\ to\ install\ it\ ---\ or\ edit\ the\ shell\ script\ to\ use\na\ different\ command\ to\ get\ the\ memory\ and\ swap\ data.\n\n***********************\nCAPTURING\ THE\ GUI\ IMAGE:\n\nA\ screen/window\ capture\ utility\ (like\ 'gnome-screenshot'\non\ Linux)\ can\ be\ used\ to\ capture\ the\ GUI\ image\ in\ a\ PNG\nor\ GIF\ file,\ say.\n\nIf\ necessary,\ an\ image\ editor\ (like\ 'mtpaint'\ on\ Linux)\ncan\ be\ used\ to\ crop\ the\ window\ capture\ image.\ \ The\ image\ncould\ also\ be\ down-sized\ ---\ say\ to\ make\ a\ smaller\ image\nsuitable\ for\ use\ in\ a\ web\ page\ or\ an\ email.\n\"\n\n\n##+################################################################\n##+################################################################\n##\ Additional\ GUI\ INITIALIZATION:\ \ Mainly\ to\n##\ \ -\ Put\ the\ 2\ meters\ on\ their\ 2\ canvases,\ with\ 'make_tachometers'.\n##\ \ -\ Start\ an\ execution\ loop\ for\ the\ 'update_needles'\ proc.\n##+################################################################\n\n##+###################################################\n##\ Set\ the\ scale\ widget\ var\ for\ initial\ 'refresh\ rate'\n##\ (actually\ wait-time\ =\ 'wave-length',\ not\ 'frequency')\n##\ ---\ in\ seconds.\n##\ COMMENTED.\ There\ were\ technical\ problems\ with\n##\ using\ a\ wait-time.\ The\ GUI\ became\ unusable\ during\n##\ the\ wait.\ A\ different\ technique\ is\ needed.\n##+###################################################\n\n#\ set\ WAITseconds\ 60.0\n\n##\ FOR\ TESTING:\n#\ \ set\ WAITseconds\ 1.0\n\n\n##+#################################################\n##\ Draw\ the\ 2\ tachometers\ (without\ needles).\n##+#################################################\n##\ Need\ 'update'\ here\ to\ set\ the\ size\ of\ the\ canvases,\n##\ because\ 'make_tachometers'\ uses\ 'winfo'\ to\ get\n##\ the\ width\ and\ height\ of\ some\ frames\ and\ canvases.\n##+#################################################\n\nupdate\nmake_tachometers\n\n\n##+#################################################\n##\ Set\ a\ resize\ binding\ on\ the\ canvas\ ---\n##\ to\ redraw\ the\ tachometers\ and\ needles\n##\ if\ the\ window\ is\ resized.\n##\n##\ DE-ACTIVATED,\ for\ now.\n##\ (Code\ is\ here\ for\ future\ experimentation.\n##\ \ It\ is\ not\ easy\ to\ avoid\ extraneous\ redraws\ of\n##\ \ the\ GUI\ as\ the\ window\ is\ being\ dragged/resized.)\n##+#################################################\n\nif\ \{0\}\ \{\nset\ draw_wait0or1\ 0\nset\ PREVcanvasesWidthPx\ \ \[winfo\ width\ \ .fRcanvases\]\nset\ PREVcanvasesHeightPx\ \[winfo\ height\ .fRcanvases\]\nbind\ .fRcanvases\ <Configure>\ \"ReDraw_if_canvases_resized\"\n\}\n\n\n##+############################################\n##\ Do\ an\ initial\ draw\ of\ the\ needles.\n##\n##\ In\ an\ attempt\ to\ use\ the\ \$WAITseconds\ var\ above,\n##\ this\ 'update_needles'\ call\ started\ a\ recursive-loop\n##\ to\ keep\ updating\ the\ needles.\n##\n##\ The\ proc\ 'update_needles'\ called\ itself,\ recursively,\n##\ after\ waiting\ \$WAITseconds.\ NOTE:\n##\n##\ I\ am\ leery\ of\ that\ kind\ of\ recursion\ leading\n##\ to\ ever-increasing\ memory\ consumption\ or\ the\n##\ generation\ of\ an\ ever-increasing\ 'stack'\ of\n##\ processes\ ---\ or\ 'stack'\ of\ 'whatever'.\n##\n##\ Before\ trying\ recursion,\ I\ tried\ a\ 'while'\ loop\n##\ here.\ \ But\ I\ needed\ to\ 'drop\ into'\ the\ Tk\ event\n##\ handling\ loop\ here,\ and\ I\ could\ not\ do\ that\n##\ if\ I\ put\ a\ 'while'\ loop\ here\ that\ keeps\n##\ calling\ 'update_needles'\ after\ a\ wait\ of\n##\ \$WAITseconds.\n##\n##\ In\ any\ case,\ even\ the\ 'recursive'\ 'update_needles'\n##\ proc\ technique\ led\ to\ GUI\ unresponsiveness\ problems,\n##\ so\ I\ went\ to\ requiring\ the\ user\ to\ use\ the\ 'Refresh'\n##\ button\ to\ do\ the\ needle\ updates.\n##+############################################\n\nupdate_needles\n\n======\n\n<<discussion>>\n\nAnd\ here\ is\ the\ code\ for\ the\ shell\ script\ called\ by\ this\ Tk\ script.\n\nYou\ can\ put\ this\ script\ in\ the\ same\ directory\ with\ the\ Tk\ script.\nThe\ Tk\ script\ includes\ some\ code\ (involving\ the\ 'argv0'\ variable)\nto\ determine\ the\ location\ of\ the\ shell\ script\ by\ extracting\ the\ name\nof\ the\ directory\ in\ which\ the\ Tk\ script\ lies.\n\n<<discussion>>Code\ for\ the\ shell\ script\ 'get_memory_and_swap.sh'\ :\n\n======\n\n#!/bin/sh\n##\n##\ SCRIPT\ NAME:\ get_memory_and_swap.sh\n##\n#############################################################################\n##\ PURPOSE:\n##\ \ \ \ Gets\ 'memory'\ and\ 'swap'\ data\ from\ output\ of\ the\ 'free'\ command.\n##\n##\ Example\ output\ from\ the\ 'free\ -m\ -o'\ command:\n##\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ total\ \ \ \ \ \ \ used\ \ \ \ \ \ \ free\ \ \ \ \ shared\ \ \ \ buffers\ \ \ \ \ cached\n##\ Mem:\ \ \ \ \ \ \ \ \ \ 3275\ \ \ \ \ \ \ \ 595\ \ \ \ \ \ \ 2679\ \ \ \ \ \ \ \ \ \ 0\ \ \ \ \ \ \ \ 114\ \ \ \ \ \ \ \ 243\n##\ Swap:\ \ \ \ \ \ \ \ \ 2290\ \ \ \ \ \ \ \ \ \ 0\ \ \ \ \ \ \ 2290\n##\n##\ where\ '-m'\ means\ the\ data\ is\ shown\ in\ megabytes\ instead\ of\ the\ default\ of\n##\ kilobytes\ ---\ and\ '-o'\ means\ that\ a\ line\ of\ buffer/cache\ data\ is\ not\ shown.\n##\n##\ This\ script\ gets\ the\ data\ from\ the\ 'total'\ and\ 'used'\ columns.\n##\n#############################################################################\n##\ CALLED\ BY:\ a\ Tk\ GUI\ script\ that\ shows\ 'memory'\ and\ 'swap'\ data\n##\ \ \ \ \ \ \ \ \ \ \ \ as\ needle\ readings\ on\ a\ couple\ of\ meters\ (dials)\ drawn\n##\ \ \ \ \ \ \ \ \ \ \ \ on\ a\ Tk\ canvas\ ---\ Tk\ script\ name:\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ meters_memory_swap.tk\n##\n#############################################################################\n##\ MAINTENANCE\ HISTORY:\n##\ Updated\ by:\ Blaise\ Montandon\ 2013aug08\ Started\ this\ script\ on\ Linux,\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ using\ Ubuntu\ 9.10\ (2009\ October,\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'Karmic\ Koala').\n##\ Updated\ by:\ Blaise\ Montandon\ 20.......\n#############################################################################\n\n##\ FOR\ TESTING:\n#\ \ set\ -x\n\n#\ FREEOUT=`free\ -m\ -o\ |\ tail\ -2\ |\ cut\ -c6-30\ |\ tr\ '\\n'\ '\ '\ |\ sed\ 's/\ \ */\ /g'`\n\nfree\ -m\ -o\ |\ tail\ -2\ |\ cut\ -c6-30\ |\ tr\ '\\n'\ '\ '\ |\ sed\ 's/\ \ */\ /g'\n\n======\n\n<<discussion>>\n\n------\n\n'''SIMILAR\ UTILITIES:'''\n\nThere\ are\ several\ more\ 'meter\ utilities'\ on\ my\ 'to-do'\ list\nat\ the\ bottom\ of\ my\ 'bio'\ page\ at\ \[uniquename\]\ ---\ in\ the\ 'CME'\ (Code\ for\nMEters)\ group.\n\nIn\ particular,\ I\ may\ make\ a\ meter\ utility\ that\ shows\ network\ activity\n---\ and\ a\ meter\ utility\ that\ shows\ CPU\ activity\ (preferably\ for\ all\ the\ CPU's\non\ multiple\ CPU\ computers,\ which\ are\ everywhere\ nowadays).\n\n------\n\n'''IN\ CONCLUSION'''\n\nAs\ I\ have\ said\ on\ several\ other\ code-donation\ pages\ on\ this\ wiki\ ...\n\nThere's\ a\ lot\ to\ like\ about\ a\ utility\ that\ is\ 'free\ freedom'\ ---\nthat\ is,\ no-cost\ and\ open-source\ so\ that\ you\ can\ modify/enhance/fix\nit\ without\ having\ to\ wait\ for\ someone\ else\ to\ do\ it\ for\ you\n(which\ may\ be\ never).\n\nA\ BIG\ THANK\ YOU\ to\ Ousterhout\ for\ starting\ Tcl-Tk,\ and\ a\ BIG\ THANK\ YOU\nto\ the\ Tcl-Tk\ developers\ and\ maintainers\ who\ have\ kept\ the\ simply\ MAH-velous\n'wish'\ interpreter\ going.\n\n----\n\n<<discussion>>\n\n\ \ \ *\ But\ I\ found\ that\ there\ were\ technical\ problems\ with\ using\ the\ wait-time.\ Namely,\ in\ my\ attempt\ at\ implementation,\ the\ GUI\ became\ essentially\ non-interactive\ during\ the\ wait\ time.\n\n\[RLE\]\ (2013-09-01):\ Your\ comment\ at\ the\ end\ of\ the\ script\ explains\ what\ was\ wrong.\ \ You\ were\ never\ actually\ dropping\ into\ the\ Tk\ event\ loop,\ which\ is\ why\ your\ GUI\ got\ \"stuck\"\ with\ automatic\ updates.\ \ What\ you\ need\ to\ do\ is:\n\n\ \ \ 1.\ reinstate\ the\ wait\ time\ variable\ as\ an\ integer\ value\ in\ milli-seconds\ of\ wait\ time\;\n\ \ \ 2.\ modify\ your\ \"update_needles\"\ proc\ to\ do,\ as\ the\ very\ last\ command\ after\ the\ proc\ finishes\ the\ rest\ of\ its\ work\ the\ following:\n\n\ \ after\ \$::WAITmilliseconds\ update_needles\n\nAnd,\ change\ the\ last\ command\ in\ your\ script\ from\ \"update_needles\"\ to\ the\ following:\n\n\ \ after\ idle\ update_needles\n\nAt\ which\ point\ you\ will\ have\ the\ auto-update\ you\ wanted,\ the\ responsive\ GUI\ you\ wanted,\ and\ not\ have\ the\ recursive\ stack\ consumption\ you\ feared\ from\ update_needles\ calling\ itself.\ \ After\ you\ make\ this\ change,\ you\ can\ reinstate\ your\ slider\ idea\ to\ modify\ the\ WAITmilliseconds\ variable\ (likely\ adjusting\ so\ that\ a\ user\ see's\ seconds\ instead\ of\ milliseconds).\n\nYou\ can\ also\ replace\ your\ existing\ \[foreach\]\ loop\ over\ the\ output\ of\ get_memory_and_swap.sh\ and\ the\ entire\ shell\ script\ itself\ with\ this\ one\ line\ of\ Tcl:\n\n======\n\ \ regexp\ \{Mem:\ +(\[0-9\]+)\ +(\[0-9\]+).*Swap:\ +(\[0-9\]+)\ +(\[0-9\]+)\}\ \[\ exec\ free\ -m\ -o\ \]\ ->\ MEMtot\ MEMused\ SWAPtot\ SWAPused\n======\n\nor\ if\ you\ prefer\ two\ lines:\n\n======\n\ \ set\ freeinfo\ \[\ exec\ free\ -m\ -o\ \]\n\ \ regexp\ \{Mem:\ +(\[0-9\]+)\ +(\[0-9\]+).*Swap:\ +(\[0-9\]+)\ +(\[0-9\]+)\}\ \$freeinfo\ ->\ MEMtot\ MEMused\ SWAPtot\ SWAPused\n======\n\n----\n\n\[uniquename\]\ 2013sep02\ -\ Thanks\ for\ the\ feedback,\ RLE.\ Finally,\nafter\ 15+\ years\ of\ Tcl-Tk\ programming,\ I\ am\ introduced\ to\ a\ use\ for\nthe\ 'after\ idle'\ command.\ (There\ is\ always\ more\ to\ be\ learned\ about\ Tcl-Tk\n---\ or\ about\ any\ programming\ language\ ---\ or\ about\ life.\ Whenever\ I\ hear/read\ of\nsomeone\ saying\ they\ are\ bored,\ I\ have\ to\ think\ they\ are\ really\ unimaginative\nat\ that\ point\ in\ their\ life\ ---\ and\ need\ to\ be\ introduced\ to\ Tcl-Tk.)\n\nI\ am\ still\ a\ little\ concerned\ about\ having\ 'update_needles'\ recursively\ncalling\ itself.\ (I\ would\ be\ 'mightily'\ concerned\ if\ the\ wait-time\ were\na\ fraction\ of\ a\ second\ ---\ but,\ in\ this\ particular\ application,\ I\ would\nprobably\ have\ the\ wait\ time\ set\ at\ about\ 2\ minutes,\ in\ most\ use\ cases.)\n\nFunny\ thing,\ though.\ This\ utility\ is\ just\ the\ thing\ to\ use\ to\ check\nif\ the\ recursive\ calls\ are\ using\ more\ and\ more\ memory.\ Just\ use\ a\ wait\ time\nof\ about\ 0.1\ second\ and\ let\ it\ run\ for\ an\ hour\ or\ two.\ Check\ the\ GUI\noccasionally\ to\ see\ if\ the\ needle(s)\ is(are)\ moving.\n\n\[RLE\]\ (2013-09-02):\ The\ \[after\]\ method\ is\ not\ recursive.\ \ \[After\]\ is\ a\ general\ delay\ and\ scheduler\ command.\ \ The\ last\ command\ of\ update_needles\"\ being\ \"after\ \$waittime\ update_needles\"\ means\ \"schedule\ a\ task\ to\ execute\ \"update_needles\"\ in\ \$waittime\ milli-seconds.\ \ No\ recursive\ calls.\ \ Once\ the\ future\ task\ is\ scheduled,\ the\ current\ update_needles\ call\ exists.\ \ At\ a\ later\ time,\ a\ new\ call\ to\ update_needles\ will\ occur\ from\ the\ Tk\ event\ loop\ machinery.\n\nEven\ if\ the\ wait\ time\ were\ 1\ milli-second,\ there\ would\ still\ be\ no\ recursive\ calling.\ The\ effect\ is\ that\ \"update_needles\"\ would\ be\ executed\ every:\ (time\ to\ perform\ update_needles)\ +\ (wait\ time\ for\ after\ command)\ seconds.\ \ So\ you\ would\ likely\ not\ get\ 1ms\ execution,\ instead\ if\ update\ needles\ takes\ 250ms,\ you'd\ get\ a\ call\ every\ 251ms.\ \ But\ no\ recursion.\n\n\[uniquename\]\ 2013sep02\ It\ still\ looks\ recursive\ to\ me\ ---\ 'update_needles'\ is\ calling\ itself.\nThe\ only\ way\ that\ it\ would\ NOT\ be\ recursive\ is\ if\ the\ 'after'\ command\ somehow\ 'killed'\nthe\ proc\ that\ is\ calling\ the\ 'after'\ command\ and,\ essentially,\ 'forks\ off'\ a\ new\n'update_needles'\ proc\ while\ 'recovering'\ any\ resources\ used\ by\ the\ previous\ call\ to\n'update_needles'.\n\nPerhaps\ I\ did\ not\ explain\ well\ what\ I\ tried,\ in\ the\ comments\ at\ the\ bottom\ of\ the\ script.\nI\ tried\ TWO\ techniques:\n\ \ \ *\ a\ 'while'\ loop\n\ \ \ *\ the\ recursive\ proc-calling-itself\ technique.\nNeither\ one\ worked\ out\ well.\ The\ GUI\ became\ unresponsive.Hence\ I\ went\ to\ the\ 'Refresh'\nbutton\ technique.\ I\ will\ try\ to\ improve\ the\ comments\ at\ the\ bottom\ of\ the\ code\ above.\n\nIn\ any\ case,\ most\ concerns\ that\ I\ have\ about\ using\ that\ proc-calling-itself\ technique\nwould\ be\ addressed\ by\ trying\ the\ experiment\ that\ I\ pointed\ out\ above.\n\nBy\ the\ say,\ in\ thinking\ about\ the\ 'after\ idle'\ usage\ that\ you\ suggested,\ I\ realized\nthat\ I\ do\ not\ need\ that.\ The\ last\ call\ in\ the\ code\ was\ to\ 'update_needles',\ and\ then\nthe\ script\ 'drops\ into'\ the\ Tk\ event\ handling\ loop\ ---\ with\ no\ need\ for\ 'after\ idle'.\n\n\[RLE\]\ (2013-09-02):\ Except\ that\ based\ upon\ your\ comments\ above,\ you\ did\ not\ actually\ try\ the\ \[after\]\ command\ method.\ \ Neither\ a\ while\ loop\ nor\ a\ recursive\ call-itself\ is\ the\ \[after\]\ command\ method.\n\nChange\ your\ script\ in\ this\ way:\n\n===none\n---\ tach.orig\ \ \ 2013-09-02\ 18:35:07.805534592\ -0400\n+++\ tach.fixed\ \ 2013-09-02\ 18:35:45.717534262\ -0400\n@@\ -1149,7\ +1149,7\ @@\n\ \ \ \ ##\ \ do\ not\ 'fall\ into'\ the\ normal\ Tk\ event\ handling\ loop.)\n\ \ \ \ ############################################################\n\ \n-\ \ \ update\n+\ \ \ after\ 5000\ update_needles\n\ \n\ \}\n\ ##\ END\ OF\ proc\ 'update_needles'\n@@\ -1674,4\ +1674,4\ @@\n\ ##\ button\ to\ do\ the\ needle\ updates.\n\ ##+############################################\n\ \n-update_needles\n+after\ idle\ update_needles\n==\n\nAnd\ you\ will\ get\ updates\ every\ 5\ seconds.\n\nThe\ key\ is\ that\ \"update_needles\"\ must\ use\ \[after\]\ to\ reschedule\ itself,\ it\ can\ not\ recursively\ call\ itself.\n\n<<categories>>\ GUI\ |\ Widget regexp2} CALL {my render {A Pair of Tachometer-style Meters --- for Memory and Swap} \[uniquename\]\ -\ 2013sep01\n\nA\ couple\ of\ months\ ago,\ I\ put\ it\ on\ my\ 'to\ do'\ list\ to\ implement\ some\npractical\ applications\ for\ the\ nice\ 'tachometer\ style'\ meter\ for\ which\nMarco\ Maggi\ provided\ a\ demo\ script\ \[http://wiki.tcl.tk/9107\]\ back\ in\ 2003.\n\nOne\ of\ the\ first\ applications\ of\ the\ meter\ that\ I\ had\ in\ mind\ was\ to\nshow\ memory\ and\ swap\ used\ on\ my\ computer\ at\ any\ time\ ---\ by\ using\ a\nTk\ script\ as\ a\ 'wrapper'\ for\ the\ 'free'\ command,\ which\ is\ available\ on\nmy\ operating\ system\ (Ubuntu\ 9.10,\ 2009\ October,\ 'Karmic\ Koala').\n\nSince\ the\ 'free'\ command\ (or\ a\ command\ returning\ similar\ data)\ is\nprobably\ available\ on\ most\ Linux,\ Unix,\ and\ BSD\ systems\ ---\ and\ since\nthe\ Apple\ Mac\ operating\ system\ is\ based\ on\ a\ BSD\ system,\ this\ utility\nis\ probably\ usable\ (with\ very\ little\ change)\ on\ Linux-Unix-BSD-Mac\ systems.\n\nBesides\ showing\ two\ 'tachometer\ style'\ meters,\ side\ by\ side,\ on\ two\nTk\ 'canvas'\ widgets\ ---\ I\ originally\ wanted\ to\ provide\ a\ 'scale'\ widget\non\ the\ GUI,\ by\ which\ the\ user\ could\ specify\ at\ any\ time\ a\ new\ 'sampling\ rate'\n(actually,\ a\ 'wait-time'\ =\ 'wave-length',\ rather\ than\ a\ 'frequency').\n\nBut\ I\ found\ that\ there\ were\ technical\ problems\ with\ using\ the\ wait-time.\nNamely,\ in\ my\ attempt\ at\ implementation,\ the\ GUI\ became\ essentially\nnon-interactive\ during\ the\ wait\ time.\n\nSo,\ for\ now,\ I\ have\ supplied\ a\ 'Refresh'\ button\ on\ the\ GUI,\ so\ that\ the\nuser\ can\ request\ at\ ANY\ TIME,\ a\ new\ set\ of\ memory\ and\ swap\ values\ to\nbe\ displayed\ on\ the\ GUI.\n\nIn\ putting\ together\ the\ code\ for\ this\ GUI,\ I\ drew\ heavily\ on\ the\n'shadow-circle'\ technique\ of\ Marco\ Maggi\ to\ make\ nice\ looking\ meters.\nAnd\ I\ included\ a\ 'red-line'\ (danger)\ area\ on\ the\ meters,\ like\ he\ did.\n\nAfter\ several\ iterations\ (including\ restructuring\ the\ procs\ a\ few\ times\nand\ revising\ the\ widgets\ available\ on\ the\ GUI),\ I\ ended\ up\ with\ the\ GUI\nseen\ in\ the\ following\ image.\n\n\[meters_MEMandSWAP_initial_screenshot_412x300.jpg\]\n\nWhen\ the\ GUI\ first\ comes\ up,\ the\ two\ meters\ (their\ canvases)\ are\ sized\nat\ 200x200\ pixels\ ---\ and\ the\ data\ shown\ is\ based\ on\ an\ initial\ execution\nof\ the\ 'free'\ command.\n\nOne\ rather\ unique\ thing\ about\ this\ implementation\ of\ the\ meters\n(something\ not\ done\ by\ Maggi\ in\ his\ demo)\ is\ that\ the\ window\ and\ the\ncanvases\ and\ the\ meters\ are\ resizable.\ In\ other\ words,\ I\ spent\ quite\na\ bit\ of\ effort\ in\ converting\ Maggi's\ procs\n\ \ \ *\ FROM\ using\ hard-coded\ numbers\ for\ making\ the\ meters\ and\ their\ needles\n\ \ \ *\ TO\ using\ variables\ that\ work\ off\ of\ queries\ on\ the\ current\ size\ of\ frame\ and\ canvas\ widgets.\n\nSo\ the\ user\ is\ able\ to\ resize\ the\ window\ and\ click\ on\ the\ 'Refresh'\ button\nto\ get\ a\ bigger\ version\ of\ the\ meters\ and\ the\ needle\ position\ ---\ as\nyou\ can\ see\ in\ the\ following\ image.\n\n\[meters_MEMandSWAP_large_screenshot_635x410.jpg\]\n\nI\ had\ hoped\ to\ come\ up\ with\ a\ technique\ to\ avoid\ the\ 'aliasing'\ effect\non\ the\ needles\ ---\ but\ you\ can\ see\ in\ this\ image\ that,\ for\ certain\nangles\ of\ the\ needles,\ there\ is\ a\ pronounced\ 'stair-step'\ effect.\n\nHowever,\ as\ 'retina\ display'\ monitors\ come\ into\ use\ more\ and\ more\n(with\ resolutions\ above\ about\ 2000x1500\ pixels),\ even\ without\ changing\nthe\ needle-drawing\ code\ in\ this\ script,\ you\ may\ find\ that\ the\n'jaggies'\ are\ hard\ to\ see.\ (I\ do\ not\ have\ such\ a\ monitor\ yet,\ so\ I\ncannot\ say\ for\ sure.)\n\n------\n\nCAPTURING\ THE\ GENERATED\ IMAGE:\n\nWhen\ you\ get\ an\ image\ that\ you\ want\ to\ save\ ---\ say,\ to\ report\ a\nmemory-leak\ problem\ for\ some\ software\ ---\ a\ screen/window\ capture\nutility\ (like\ 'gnome-screenshot'\ on\ Linux)\ can\ be\ used\ to\ capture\nthe\ GUI\ image\ in\ a\ PNG\ or\ GIF\ file,\ say.\n\nIf\ necessary,\ an\ image\ editor\ (like\ 'mtpaint'\ on\ Linux)\ncan\ be\ used\ to\ crop\ the\ window\ capture\ image.\ \ The\ image\ncould\ also\ be\ down-sized\ ---\ say\ to\ make\ a\ smaller\ image\ suitable\ for\npresentation\ in\ an\ email\ or\ on\ a\ web\ page.\n\n------\n\nA\ LITTLE\ MEMORY\ EXPERIMENT:\n\nTo\ get\ the\ memory\ figures\ to\ change,\ I\ tried\ bringing\ up\ an\ instance\nof\ the\ Seamonkey\ web\ browser\ on\ my\ computer\ and\ then\ clicking\ on\ the\n'Refresh'\ button.\ I\ found\ that\ for\ each\ new\ instance\ of\ Seamonkey\nthat\ I\ started\ (I\ started\ about\ seven),\ the\ memory\ usage\ went\ up\nabout\ 2\ to\ 10\ Megabytes.\n\nAt\ that\ level\ of\ memory\ consumption,\ the\ percent-needle\ hardly\ moved,\nbecause\ 10/3000\ is\ less\ than\ one-half\ of\ one\ percent.\n\n------\n\n'''The\ code'''\n\nBelow,\ I\ provide\ the\ Tk\ script\ code\ for\ this\ 'memory-and-swap\ in\ tachometers'\ndisplay\ utility.\n\nI\ follow\ my\ usual\ 'canonical'\ structure\ for\ Tk\ code\ for\ this\ Tk\ script:\n\n\ \ 0)\ Set\ general\ window\ &\ widget\ parms\ (win-name,\ win-position,\n\ \ \ \ \ win-color-scheme,\ fonts,\ widget-geometry-parms,\ win-size-control,\n\ \ \ \ \ text-array-for-labels-etc).\n\n\ \ 1a)\ Define\ ALL\ frames\ (and\ sub-frames,\ if\ any).\n\ \ 1b)\ Pack\ \ \ ALL\ frames\ and\ sub-frames.\n\n\ \ 2)\ Define\ &\ pack\ all\ widgets\ in\ the\ frames,\ frame\ by\ frame.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Within\ each\ frame,\ define\ ALL\ the\ widgets.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Then\ pack\ the\ widgets.\n\n\ \ 3)\ Define\ keyboard\ and\ mouse/touchpad/touch-sensitive-screen\ action\n\ \ \ \ \ BINDINGS,\ if\ needed.\n\n\ \ 4)\ Define\ PROCS,\ if\ needed.\n\n\ \ 5)\ Additional\ GUI\ initialization\ (typically\ with\ one\ or\ more\ of\n\ \ \ \ \ the\ procs),\ if\ needed.\n\nThis\ Tk\ coding\ structure\ is\ discussed\ in\ more\ detail\ on\ the\ page\n\[A\ Canonical\ Structure\ for\ Tk\ Code\ ---\ and\ variations\].\n\nThis\ structure\ makes\ it\ easy\ for\ me\ to\ find\ code\ sections\ ---\ while\ngenerating\ and\ testing\ a\ Tk\ script,\ and\ when\ looking\ for\ code\ snippets\nto\ include\ in\ other\ scripts\ (code\ re-use).\n\nI\ call\ your\ attention\ to\ step-zero.\nOne\ new\ thing\ that\ I\ have\ started\ doing\ recently\ is\ using\ a\ text-array\nfor\ text\ in\ labels,\ buttons,\ and\ other\ widgets\ in\ the\ GUI.\nThis\ can\ make\ it\ easier\ for\ people\ to\ internationalize\ my\ scripts.\nI\ will\ be\ using\ a\ text-array\ like\ this\ in\ most\ of\ my\ scripts\ in\ the\ future.\n\n------\n\n'''Experimenting\ with\ the\ GUI'''\n\nAs\ in\ all\ my\ scripts\ that\ use\ the\ 'pack'\ geometry\ manager\ (which\ is\ all\nof\ my\ 100-plus\ scripts,\ so\ far),\ I\ provide\ the\ four\ main\ pack\ parameters\n---\ '-side',\ '-anchor',\ '-fill',\ '-expand'\ ---\ on\ all\ of\ the\ 'pack'\ncommands\ for\ the\ frames\ and\ widgets.\n\nThat\ helps\ me\ when\ I\ am\ initially\ testing\ the\ behavior\ of\ a\ GUI\n(the\ various\ widgets\ within\ it)\ as\ I\ resize\ the\ main\ window.\n\nI\ think\ that\ I\ have\ used\ a\ pretty\ nice\ choice\ of\ the\ 'pack'\ parameters.\nThe\ label\ and\ button\ widgets\ stay\ fixed\ in\ size\ and\ relative-location\nif\ the\ window\ is\ re-sized\ ---\ while\ the\ two\ canvas\ areas\ (without\ scroll\ bars)\nexpand/contract\ whenever\ the\ window\ is\ re-sized,\ and\ the\ 'Refresh'\ button\nis\ clicked.\n\nThe\ meters\ expand/contract\ when\ the\ window\ is\ re-sized\ ---\ but\ probably\nnot\ always\ in\ a\ way\ you\ would\ expect.\ Occasionally,\ you\ may\ need\ to\ tug\nthe\ borders\ of\ the\ window\ to\ center\ the\ meters\ in\ a\ way\ that\ suits\ you.\n\nYou\ can\ experiment\ with\ the\ \ '-side',\ '-anchor',\ '-fill',\nand\ '-expand'\ parameters\ on\ the\ 'pack'\ commands\ for\ the\ various\nframes\ and\ widgets\ ---\ to\ get\ the\ widget\ behavior\ that\ you\ want.\n\nAnd\ you\ can\ look\ into\ the\ code\ that\ is\ drawing\ the\ meters\ to\ see\ if\ you\ncan\ devise\ meter-resizing\ behavior\ that\ pleases\ you\ more.\n\n___\n\nAdditional\ experimentation:\ You\ might\ want\ to\ change\ the\ fonts\ used\ for\nthe\ various\ GUI\ widgets.\ For\ example,\ you\ could\ change\ '-weight'\nfrom\ 'bold'\ to\ 'normal'\ ---\ or\ '-slant'\ from\ 'roman'\ to\ 'italic'.\nOr\ change\ font\ families.\n\nIn\ fact,\ you\ may\ NEED\ to\ change\ the\ font\ families,\ because\nthe\ families\ I\ used\ may\ not\ be\ available\ on\ your\ computer\ ---\nand\ the\ default\ font\ that\ the\ 'wish'\ interpreter\ chooses\ may\ not\nbe\ very\ pleasing.\n\nI\ use\ variables\ to\ set\ geometry\ parameters\ of\ widgets\ ---\nparameters\ such\ as\ border-widths\ and\ padding.\ And\ I\ have\ included\nthe\ '-relief'\ parameter\ on\ the\ definitions\ of\ frames\ and\ widgets.\nFeel\ free\ to\ experiment\ with\ those\ 'appearance'\ parameters\ as\ well.\n\n------\n\n'''Some\ features\ in\ the\ code'''\n\nThat\ said,\ here's\ the\ code\ ---\ with\ plenty\ of\ comments\ to\ describe\nwhat\ most\ of\ the\ code-sections\ are\ doing.\n\nYou\ can\ look\ at\ the\ top\ of\ the\ PROCS\ section\ of\ the\ code\ to\ see\ a\nlist\ of\ the\ procs\ used\ in\ this\ script,\ along\ with\ brief\ descriptions\nof\ how\ they\ are\ called\ and\ what\ they\ do.\n\nThe\ main\ procs\ are\n\n\ \ \ 'make_tachometers'\ -\ to\ draw\ 2\ meters\ within\ their\ 2\ Tk\ (square)\ canvases.\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (We\ may\ allow\ the\ 2\ canvases\ to\ resize\ according\ to\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ a\ resizing\ of\ the\ window.\ This\ proc\ will\ set\ the\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ SQUARE\ size\ of\ the\ 2\ canvases\ according\ to\ the\ current\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size\ of\ the\ frame\ containing\ the\ 2\ canvases.)\n\n\ \ \ 'make_one_tachometer'\ -\ called\ by\ 'make_tachometers',\ to\ make\ each\ meter.\n\n\ \ \ 'draw_rivet'\ \ \ \ \ \ -\ called\ by\ 'make_one_tachometer',\ 4\ times,\ to\ put\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rivets\ in\ 4\ corners\ around\ a\ meter.\n\n\ \ \ 'draw_circle_shadow'\ \ -\ called\ by\ 'make_one_tachometer'\ to\ put\ a\ shadowed\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ edge\ around\ the\ circle\ that\ makes\ the\ meter.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Also\ called\ to\ help\ make\ a\ 'pin'\ in\ the\ center\ of\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ meter\ to\ hold\ the\ needle.\ Also\ called\ to\ make\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ 4\ rivets.\n\n\ \ \ 'update_needles'\ \ \ \ \ \ -\ to\ update\ the\ needles\ on\ the\ 2\ meters.\n\n\ \ \ 'update_one_needle'\ \ \ -\ called\ by\ 'update_needles',\ to\ draw\ each\ needle.\n\n\ \ \ 'Refresh'\ \ \ \ \ \ \ \ \ \ \ \ \ -\ called\ by\ 'Refresh'\ button.\ Runs\ 'make_tachometers'\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ and\ 'update_needles'.\ \ \n\n\ \ \ 'popup_msgVarWithScroll'\ -\ called\ by\ the\ 'Help'\ button,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ to\ show\ text\ in\ variable\ \$HELPtext.\n\nThanks\ to\ Marco\ Maggi\ whose\ 'shadow-circle'\ drawing\ technique\ and\ code\nmade\ this\ script\ much\ easier\ to\ write.\n\n-----\n\nIt\ is\ my\ hope\ that\ the\ copious\ comments\ in\ the\ code\ will\ help\ Tcl-Tk\ncoding\ 'newbies'\ get\ started\ in\ making\ GUI's\ like\ this.\n\nWithout\ the\ comments,\ potential\ young\ Tcler's\ might\ be\ tempted\ to\nreturn\ to\ their\ iPhones\ and\ iPads\ and\ iPods\ ---\ to\ watch\ videos\ of\nskydiving\ free\ falls\ gone\ scarily\ wrong.\ (Anyone\ see\ the\ video\ of\nthe\ old\ grandmother\ who\ almost\ slips\ out\ of\ the\ harness\ and\ grasp\ of\ the\nskydiving\ instructor\ who\ no\ doubt\ assured\ her\ that\ there's\ nothing\nto\ worry\ about?)\n\n------\n\n<<discussion>>Code\ for\ Tk\ script\ 'meters_memory_swap.tk'\ :\n\n======\n\n#!/usr/bin/wish\ -f\n##+########################################################################\n##\n##\ SCRIPT:\ meters_memory_swap.tk\n##\n##\ PURPOSE:\ This\ script\ is\ meant\ to\ show\ a\ GUI\ that\ holds\ a\ pair\ of\n##\ \ \ \ \ \ \ \ \ \ tachometer-style\ meters.\ The\ needles\ on\ the\ meters\ can\ be\ updated\n##\ \ \ \ \ \ \ \ \ \ periodically\ to\ show\ the\ amount\ of\ memory\ and\ swap\ in\ use.\n##\n##\ \ \ \ \ \ \ \ \ \ This\ script\ was\ developed\ on\ Linux\ and\ uses\ the\ 'free'\n##\ \ \ \ \ \ \ \ \ \ command\ to\ periodically\ get\ the\ memory\ and\ swap\ data\ to\n##\ \ \ \ \ \ \ \ \ \ determine\ where\ to\ relocate\ the\ position\ of\ the\ needles.\n##\n##+################\n##\ GUI\ DESCRIPTION:\n##\n##\ \ \ \ \ \ \ \ \ This\ script\ provides\ a\ Tk\ GUI\ with\ the\ following\ widgets.\n##\n##\ \ \ \ \ \ \ \ \ 1)\ There\ is\ an\ 'fRbuttons'\ frame\ to\ hold\ BUTTONS\ such\ as\n##\ \ \ \ \ \ \ \ \ \ \ \ 'Exit'\ and\ 'Help'\ buttons\ ---\ as\ well\ as\ a\ 'Refresh'\n##\ \ \ \ \ \ \ \ \ \ \ \ button.\n##\n##\ \ \ \ \ \ \ \ \ \ \ \ (Someday,\ I\ would\ like\ to\ implement\ a\ SCALE\ widget\ for\ the\n##\ \ \ \ \ \ \ \ \ \ \ \ \ user\ to\ set\ a\ 'wait-seconds'\ for\ auto-refresh\ of\ the\ meters\ ---\n##\ \ \ \ \ \ \ \ \ \ \ \ \ in\ seconds\ ---\ down\ to\ tenths\ of\ seconds,\ and\ up\ to\ multiple\n##\ \ \ \ \ \ \ \ \ \ \ \ \ minutes.\ But\ I\ hit\ technical\ problems.\ Perhaps\ later.)\n##\n##\ \ \ \ \ \ \ \ \ 2)\ There\ is\ an\ 'fRcanvases'\ frame\ to\ contain\ 2\ CANVAS\ widgets\ that\n##\ \ \ \ \ \ \ \ \ \ \ \ hold\ the\ two\ meter\ images,\ in\ 2\ SQUARE\ canvases,\ side\ by\ side.\n##\ \ \ \ \ \ \ \ \ \ \ \ Also\ the\ 'fRcanvases'\ frame\ holds\ some\ LABEL\ widgets,\ to\ show\n##\ \ \ \ \ \ \ \ \ \ \ \ TOTAL-and-USED\ MEMORY\ and\ TOTAL-and-USED\ SWAP,\ as\ text\ items.\n##\n##+################################\n##\ METHOD\ USED\ to\ update\ the\ meters:\n##\n##\ \ \ \ A\ Tcl\ 'exec'\ command\ calls\ on\ a\ separate\ shell\ script\ that\ uses\n##\ \ \ \ the\ 'free'\ command\ to\ get\ the\ memory\ and\ swap\ data\ and\n##\ \ \ \ extract-and-format\ the\ data\ for\ return\ to\ this\ Tk\ script.\n##\n##+#######################\n##\ CAPTURING\ THE\ GUI\ IMAGE:\n##\n##\ \ \ A\ screen/window\ capture\ utility\ (like\ 'gnome-screenshot'\n##\ \ \ on\ Linux)\ can\ be\ used\ to\ capture\ the\ GUI\ image\ in\ a\ PNG\n##\ \ \ or\ GIF\ file,\ say.\n##\n##\ \ \ If\ necessary,\ an\ image\ editor\ (like\ 'mtpaint'\ on\ Linux)\n##\ \ \ can\ be\ used\ to\ crop\ the\ window\ capture\ image.\ \ The\ image\n##\ \ \ could\ also\ be\ down-sized\ ---\ say\ to\ make\ a\ smaller\ image\n##\ \ \ suitable\ for\ use\ in\ a\ web\ page\ or\ an\ email.\n##\n##+#######################################################################\n##\ 'CANONICAL'\ STRUCTURE\ OF\ THIS\ CODE:\n##\n##\ \ 0)\ Set\ general\ window\ parms\ (win-name,\ win-position,\ win-color-scheme,\n##\ \ \ \ \ fonts,\ widget-geom-parms,\ win-size-control,\ text-array-for-labels-etc).\n##\n##\ \ 1a)\ Define\ ALL\ frames\ (and\ sub-frames,\ if\ any).\n##\ \ 1b)\ Pack\ the\ frames.\n##\n##\ \ 2)\ Define\ &\ pack\ all\ widgets\ in\ the\ frames,\ frame\ by\ frame.\n##\ \ \ \ \ After\ all\ the\ widgets\ for\ a\ frame\ are\ defined,\ pack\ them\ in\ the\ frame.\n##\n##\ \ 3)\ Define\ keyboard\ or\ mouse/touchpad/touch-sensitive-screen\ 'event'\n##\ \ \ \ \ BINDINGS,\ if\ needed.\n##\n##\ \ 4)\ Define\ PROCS,\ if\ needed.\n##\n##\ \ 5)\ Additional\ GUI\ INITIALIZATION\ (typically\ with\ one\ or\ more\ of\n##\ \ \ \ \ the\ procs),\ if\ needed.\n##\n##+#################################\n##\ Some\ detail\ of\ the\ code\ structure\ of\ this\ particular\ script:\n##\n##\ \ 1a)\ Define\ ALL\ frames:\n##\ \n##\ \ \ Top-level\ :\n##\ \ \ \ \ \ '.fRbuttons'\ \ -\ to\ contain\ a\ widget\ to\ set\ the\ refresh-rate,\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ as\ well\ as\ contain\ 'Exit'\ and\ 'Help'\ buttons.\n##\ \ \ \ \ \ '.fRcanvases'\ -\ to\ contain\ 2\ canvas\ widgets,\ which\ will\ display\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ two\ meters,\ side-by-side.\n##\n##\ \ \ Sub-frames:\n##\ \ \ \ \ \ \ '.fRcanvases.fRcanvas1'\ -\ for\ 2\ label\ widgets\ &\ 1\ canvas\ widget\n##\ \ \ \ \ \ \ '.fRcanvases.fRcanvas2'\ -\ for\ 2\ label\ widgets\ &\ 1\ canvas\ widget\n##\n##\ \ 1b)\ Pack\ ALL\ frames.\n##\n##\ \ 2)\ Define\ &\ pack\ all\ widgets\ in\ the\ frames\ --\ basically\ going\ through\n##\ \ \ \ \ frames\ &\ their\ interiors\ in\ \ left-to-right,\ or\ top-to-bottom\ order.\n##\n##\ \ 3)\ Define\ BINDINGS:\ \ none\n##\n##\ \ 4)\ Define\ PROCS:\n##\n##\ \ \ \ 'make_tachometers'\ -\ to\ draw\ 2\ meters\ within\ their\ 2\ Tk\ (square)\ canvases.\n##\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (We\ may\ allow\ the\ 2\ canvases\ to\ resize\ according\ to\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ a\ resizing\ of\ the\ window.\ This\ proc\ will\ set\ the\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ SQUARE\ size\ of\ the\ 2\ canvases\ according\ to\ the\ current\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size\ of\ the\ frame\ containing\ the\ 2\ canvases.)\n##\n##\ \ \ \ 'make_one_tachometer'\ -\ called\ by\ 'make_tachometers',\ to\ make\ each\ meter.\n##\n##\ \ \ \ 'draw_rivet'\ \ \ \ \ \ -\ called\ by\ 'make_one_tachometer',\ 4\ times,\ to\ put\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rivets\ in\ 4\ corners\ around\ a\ meter.\n##\n##\ \ \ \ 'draw_circle_shadow'\ \ -\ called\ by\ 'make_one_tachometer'\ to\ put\ a\ shadowed\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ edge\ around\ the\ circle\ that\ makes\ the\ meter.\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Also\ called\ to\ help\ make\ a\ 'pin'\ in\ the\ center\ of\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ meter\ to\ hold\ the\ needle.\ Also\ called\ to\ make\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ 4\ rivets.\n##\n##\ \ \ \ 'update_needles'\ \ \ \ \ \ -\ to\ update\ the\ needles\ on\ the\ 2\ meters.\n##\n##\ \ \ \ 'update_one_needle'\ \ \ -\ called\ by\ 'update_needles',\ to\ draw\ each\ needle.\n##\n##\ \ \ \ 'Refresh'\ \ \ \ \ \ \ \ \ \ \ \ \ -\ called\ by\ 'Refresh'\ button.\ Runs\ 'make_tachometers'\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ and\ 'update_needles'.\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n##\n##\ \ \ 'popup_msgVarWithScroll'\ -\ called\ by\ 'Help'\ button\ to\ show\ HELPtext\ var.\n##\ \ \ \ \ \ \ \ \ \n##\n##\ \ 5)\ Additional\ GUI\ Initialization:\n##\ \ \ \ \ \ \ \ -\ call\ 'make_tachometers'\ to\ put\ the\ 2\ meters\ on\ the\ canvas\n##\ \ \ \ \ \ \ \ -\ call\ 'update_needles'\ ---\ to\ initialize\ the\ needle\ locations.\n##\n##+#######################################################################\n##\ DEVELOPED\ WITH:\ Tcl-Tk\ 8.5\ on\ Ubuntu\ 9.10\ (2009-october,\ 'Karmic\ Koala')\n##\n##\ \ \ \$\ wish\n##\ \ \ %\ puts\ \"\$tcl_version\ \$tk_version\"\n##\n##\ showed\n##\ \ \ \ \ 8.5\ 8.5\n##\ but\ this\ script\ should\ work\ in\ most\ previous\ 8.x\ versions,\ and\ probably\n##\ even\ in\ some\ 7.x\ versions\ (if\ font\ handling\ is\ made\ 'old-style').\n##+#######################################################################\n##\ MAINTENANCE\ HISTORY:\n##\ Started\ by:\ Blaise\ Montandon\ 2013jul29\ Started\ the\ basic\ code\ of\ the\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ script\ based\ on\ the\ tachometer\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ demo\ script\ by\ Marco\ Maggi\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ at\ http://wiki.tcl.tk/9107\n##\ Changed\ by:\ Blaise\ Montandon\ 2013aug30\ Get\ most\ of\ the\ GUI\ working,\ using\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ an\ appropriate\ hierarchy\ of\ procs.\n##\ Changed\ by:\ Blaise\ Montandon\ 2013sep01\ Settled\ on\ using\ a\ 'Refresh'\ button,\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ instead\ of\ a\ scale\ widget\ with\ a\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ WAITseconds\ variable.\n##+########################################################################\n\n##+######################################################\n##\ Set\ WINDOW\ TITLE\ and\ POSITION.\n##+######################################################\n\nwm\ title\ \ \ \ .\ \"Percent\ of\ Total\ Memory\ &\ Swap\ in\ Use\"\nwm\ iconname\ .\ \"MemSwap\"\n\nwm\ geometry\ .\ +15+30\n\n\n##+######################################################\n##\ Set\ the\ COLOR\ SCHEME\ for\ the\ window\ and\ its\ widgets\ ---\n##\ such\ as\ listbox\ and\ entry\ field\ background\ color.\n##+######################################################\n\ntk_setPalette\ \"#e0e0e0\"\n\n#\ set\ listboxBKGD\ \"#ffffff\"\n#\ set\ entryBKGD\ \"#ffffff\"\n\ \ set\ scaleBKGD\ \"#f0f0f0\"\n\n##+########################################################\n##\ DEFINE\ (temporary)\ FONT\ NAMES.\n##\n##\ We\ use\ a\ VARIABLE-WIDTH\ font\ for\ text\ on\ LABEL\ and\n##\ BUTTON\ widgets.\n##\n##\ We\ use\ a\ FIXED-WIDTH\ font\ for\ LISTBOX\ lists,\n##\ for\ Help-text\ in\ a\ TEXT\ widget,\ and\ for\n##\ the\ text\ in\ ENTRY\ fields,\ if\ any.\n##+########################################################\n\nfont\ create\ fontTEMP_varwidth\ \\\n\ \ \ -family\ \{comic\ sans\ ms\}\ \\\n\ \ \ -size\ -14\ \\\n\ \ \ -weight\ bold\ \\\n\ \ \ -slant\ roman\n\nfont\ create\ fontTEMP_SMALL_varwidth\ \\\n\ \ \ -family\ \{comic\ sans\ ms\}\ \\\n\ \ \ -size\ -12\ \\\n\ \ \ -weight\ bold\ \\\n\ \ \ -slant\ roman\n\n##\ Some\ other\ possible\ (similar)\ variable\ width\ fonts:\n##\ \ Arial\n##\ \ Bitstream\ Vera\ Sans\n##\ \ DejaVu\ Sans\n##\ \ Droid\ Sans\n##\ \ FreeSans\n##\ \ Liberation\ Sans\n##\ \ Nimbus\ Sans\ L\n##\ \ Trebuchet\ MS\n##\ \ Verdana\n\n\nfont\ create\ fontTEMP_fixedwidth\ \ \\\n\ \ \ -family\ \{liberation\ mono\}\ \\\n\ \ \ -size\ -14\ \\\n\ \ \ -weight\ bold\ \\\n\ \ \ -slant\ roman\n\nfont\ create\ fontTEMP_SMALL_fixedwidth\ \ \\\n\ \ \ -family\ \{liberation\ mono\}\ \\\n\ \ \ -size\ -12\ \\\n\ \ \ -weight\ bold\ \\\n\ \ \ -slant\ roman\n\n##\ Some\ other\ possible\ fixed\ width\ fonts\ (esp.\ on\ Linux):\n##\ \ Andale\ Mono\n##\ \ Bitstream\ Vera\ Sans\ Mono\n##\ \ Courier\ 10\ Pitch\n##\ \ DejaVu\ Sans\ Mono\n##\ \ Droid\ Sans\ Mono\n##\ \ FreeMono\n##\ \ Nimbus\ Mono\ L\n##\ \ TlwgMono\n\n\n##+###########################################################\n##\ SET\ GEOM\ VARS\ FOR\ THE\ VARIOUS\ WIDGET\ DEFINITIONS.\n##\ (e.g.\ width\ and\ height\ of\ canvas,\ and\ padding\ for\ Buttons)\n##+###########################################################\n\n##\ CANVAS\ widget\ geom\ settings:\n\nset\ initCanWidthPx\ \ 200\nset\ initCanHeightPx\ 200\n\nset\ minCanWidthPx\ \ 24\nset\ minCanHeightPx\ 24\n\n#\ set\ BDwidthPx_canvas\ 2\n\ \ set\ BDwidthPx_canvas\ 0\n\n\n##\ BUTTON\ widget\ geom\ settings:\n\nset\ PADXpx_button\ 0\nset\ PADYpx_button\ 0\nset\ BDwidthPx_button\ 2\n\n\n##\ LABEL\ widget\ geom\ settings:\n\nset\ PADXpx_label\ 0\nset\ PADYpx_label\ 0\nset\ BDwidthPx_label\ 2\n\n\n##\ SCALE\ widget\ geom\ parameters:\n\nset\ BDwidthPx_scale\ 2\nset\ initScaleLengthPx\ 200\nset\ scaleThicknessPx\ 10\n\n\n##+######################################################################\n##\ Set\ a\ MIN-SIZE\ of\ the\ window\ (roughly).\n##\n##\ For\ WIDTH,\ allow\ for\ the\ min-width\ of\ the\ '.fRbuttons'\ and\ '.fRcanvas'\n##\ frames\ ---\ at\ least,\ the\ widgets\ in\ the\ 'fRbuttons'\ frame.\n##\n##\ For\ HEIGHT,\ allow\ for\ the\ stacked\ frames:\n##\ \ \ \ \ \ \ \ \ \ \ \ 2\ chars\ \ high\ for\ the\ '.fRbuttons'\ frame,\n##\ \ at\ least\ 50\ pixels\ high\ for\ the\ '.fRcanvas'\ \ frame.\n##+#####################################################################\n\n##\ FOR\ WIDTH:\n\nset\ minWidthPx\ \[font\ measure\ fontTEMP_varwidth\ \\\n\ \ \ \"\ Exit\ \ Help\ \ Refresh\ \"\]\n\n##\ If\ we\ had\ used\ the\ scale\ widget,\ we\ would\ accomodate\ and\ label\n##\ and\ add\ pixels\ for\ length\ of\ the\ scale\ widget,\ at\ least\ 100.\n##\n##\ For\ now,\ we\ simply\ add\ some\ pixels\ to\ account\ for\ right-left-size\ of\n##\ window-manager\ decoration\ (~8\ pixels)\ and\ some\ pixels\ for\n##\ frame/widget\ borders\ (~3\ widgets\ x\ 4\ pixels/widget\ =\ 12\ pixels).\n\nset\ minWinWidthPx\ \[expr\ \{20\ +\ \$minWidthPx\}\]\n\n\n##\ For\ HEIGHT\ ---\ for\n##\ \ \ \ 2\ char\ \ \ high\ for\ 'fRbuttons'\n##\ \ \ 50\ pixels\ high\ for\ 'fRcanvas'\n\nset\ charHeightPx\ \[font\ metrics\ fontTEMP_varwidth\ -linespace\]\n\nset\ minWinHeightPx\ \[expr\ \{2\ *\ \$charHeightPx\}\]\n\n##\ Add\ about\ 50\ pixels\ for\ height\ of\ the\ canvas\n##\ AND\ add\ about\ 20\ pixels\ for\ top-bottom\ window\ decoration\ --\n##\ and\ some\ pixels\ for\ top-and-bottom\ of\ frame/widget\ borders\n##\ (~4\ widgets\ x\ 4\ pixels/widget\ =\ 16\ pixels).\n\nset\ minWinHeightPx\ \[expr\ \{86\ +\ \$minWinHeightPx\}\]\n\n\n##\ FOR\ TESTING:\n#\ \ \ puts\ \"minWinWidthPx\ =\ \$minWinWidthPx\"\n#\ \ \ puts\ \"minWinHeightPx\ =\ \$minWinHeightPx\"\n\nwm\ minsize\ .\ \$minWinWidthPx\ \$minWinHeightPx\n\n\n##\ We\ may\ allow\ the\ window\ to\ be\ resizable.\ \ We\ pack\ the\ canvases\n##\ (and\ the\ frames\ that\ contain\ them)\ with\ '-fill\ both\ -expand\ 1'\n##\ so\ that\ the\ canvases\ can\ be\ enlarged\ by\ enlarging\ the\ window.\n\n##\ If\ you\ want\ to\ make\ the\ window\ un-resizable,\ \n##\ you\ can\ use\ the\ following\ statement.\n#\ \ \ wm\ resizable\ .\ 0\ 0\n\n\n##+##############################################################\n##\ Set\ a\ TEXT-ARRAY\ to\ hold\ text\ for\ buttons\ &\ labels\ on\ the\ GUI.\n##\ \ \ \ \ NOTE:\ This\ can\ aid\ INTERNATIONALIZATION.\ This\ array\ can\n##\ \ \ \ \ \ \ \ \ \ \ be\ set\ according\ to\ a\ nation/region\ parameter.\n##+##############################################################\n\n##\ if\ \{\ \"\$VARlocale\"\ ==\ \"en\"\}\n\n##\ For\ '.fRbuttons'\ frame:\n\nset\ aRtext(buttonEXIT)\ \ \"Exit\"\nset\ aRtext(buttonHELP)\ \ \"Help\"\n\nset\ aRtext(buttonREFRESH)\ \ \"Refresh\"\n\n#\ set\ aRtext(labelSCALE)\ \ \"Refresh\ rate\n#\ (seconds)\ :\"\n\n##\ END\ OF\ \ if\ \{\ \"\$VARlocale\"\ ==\ \"en\"\}\n\n\n##+################################################################\n##\ DEFINE\ *ALL*\ THE\ FRAMES:\n##\n##\ \ \ Top-level\ :\ '.fRbuttons'\ ,\ '.fRcanvases'\n##\n##\ \ \ Sub-frames:\ '.fRcanvases.fRcanvas1'\ \ '.fRcanvases.fRcanvas2'\ \n##+################################################################\n\n##\ FOR\ TESTING:\ (to\ see\ size\ of\ frames\ as\ window\ is\ resized)\n#\ set\ BDwidth_frame\ 2\n#\ set\ RELIEF_frame\ raised\n\n\ \ set\ BDwidth_frame\ 0\n\ \ set\ RELIEF_frame\ flat\n\nframe\ .fRbuttons\ \ \ -relief\ \$RELIEF_frame\ \ -bd\ \$BDwidth_frame\nframe\ .fRcanvases\ \ -relief\ \$RELIEF_frame\ \ -bd\ \$BDwidth_frame\n\nframe\ .fRcanvases.fRcanvas1\ \ -relief\ raised\ \ -bd\ 2\nframe\ .fRcanvases.fRcanvas2\ \ -relief\ raised\ \ -bd\ 2\n\n\n##+##############################\n##\ PACK\ the\ FRAMES.\ \n##+##############################\n\npack\ .fRbuttons\ \\\n\ \ \ -side\ top\ \\\n\ \ \ -anchor\ nw\ \\\n\ \ \ -fill\ x\ \\\n\ \ \ -expand\ 0\n\npack\ .fRcanvases\ \\\n\ \ \ -side\ top\ \\\n\ \ \ -anchor\ nw\ \\\n\ \ \ -fill\ both\ \\\n\ \ \ -expand\ 1\n\npack\ .fRcanvases.fRcanvas1\ \\\n\ \ \ -side\ left\ \\\n\ \ \ -anchor\ nw\ \\\n\ \ \ -fill\ both\ \\\n\ \ \ -expand\ 1\n\npack\ .fRcanvases.fRcanvas2\ \\\n\ \ \ -side\ right\ \\\n\ \ \ -anchor\ ne\ \\\n\ \ \ -fill\ both\ \\\n\ \ \ -expand\ 1\n\n\n\n##+##########################################################\n##\ The\ FRAMES\ ARE\ PACKED.\ START\ PACKING\ WIDGETS\ IN\ THE\ FRAMES.\n##+##########################################################\n\n##+##########################################################\n##\ In\ FRAME\ '.fRbuttons'\ -\n##\ DEFINE-and-PACK\ 'BUTTON'\ WIDGETS\n##\ ---\ Exit,\ Help,\ ...\ ---\ and\ a\ LABEL-AND-SCALE\ widget\ pair\n##\ (for\ changing\ the\ 'refresh\ rate'\ for\ the\ meter\ needles.\n##+##########################################################\n\nbutton\ .fRbuttons.buttEXIT\ \\\n\ \ \ -text\ \"\$aRtext(buttonEXIT)\"\ \\\n\ \ \ -font\ fontTEMP_varwidth\ \\\n\ \ \ -padx\ \$PADXpx_button\ \\\n\ \ \ -pady\ \$PADYpx_button\ \\\n\ \ \ -relief\ raised\ \\\n\ \ \ -bd\ \$BDwidthPx_button\ \\\n\ \ \ -command\ \{set\ loop0or1\ 0\ \;\ exit\}\n\nbutton\ .fRbuttons.buttHELP\ \\\n\ \ \ -text\ \"\$aRtext(buttonHELP)\"\ \\\n\ \ \ -font\ fontTEMP_varwidth\ \\\n\ \ \ -padx\ \$PADXpx_button\ \\\n\ \ \ -pady\ \$PADYpx_button\ \\\n\ \ \ -relief\ raised\ \\\n\ \ \ -bd\ \$BDwidthPx_button\ \\\n\ \ \ -command\ \{popup_msgVarWithScroll\ .topHelp\ \"\$HELPtext\"\}\n\n\nbutton\ .fRbuttons.buttREFRESH\ \\\n\ \ \ -text\ \"\$aRtext(buttonREFRESH)\"\ \\\n\ \ \ -font\ fontTEMP_varwidth\ \\\n\ \ \ -padx\ \$PADXpx_button\ \\\n\ \ \ -pady\ \$PADYpx_button\ \\\n\ \ \ -relief\ raised\ \\\n\ \ \ -bd\ \$BDwidthPx_button\ \\\n\ \ \ -command\ \{Refresh\}\n\n\n##\ We\ DE-ACTIVATE\ this\ scale\ widget\ until\ a\ way\ of\ using\n##\ the\ WAITseconds\ variable\ can\ be\ devised\ such\ that\n##\ the\ GUI\ does\ not\ become\ unusable\ during\ the\ wait.\n\nif\ \{0\}\ \{\nlabel\ .fRbuttons.labelSCALE\ \\\n\ \ \ -text\ \"\$aRtext(labelSCALE)\"\ \\\n\ \ \ -font\ fontTEMP_SMALL_varwidth\ \\\n\ \ \ -justify\ left\ \\\n\ \ \ -anchor\ w\ \\\n\ \ \ -relief\ flat\ \\\n\ \ \ -padx\ \$PADXpx_label\ \\\n\ \ \ -pady\ \$PADYpx_label\ \\\n\ \ \ -bd\ \$BDwidthPx_label\n\n\n##\ Set\ this\ widget\ var\ in\ the\ GUI\ initialization\ section\n##\ at\ the\ bottom\ of\ this\ script.\n#\ set\ WAITseconds\ 50\n\nscale\ .fRbuttons.scaleSECONDS\ \\\n\ \ \ -from\ 0.1\ -to\ 120.0\ \\\n\ \ \ -resolution\ 0.1\ \\\n\ \ \ -font\ fontTEMP_SMALL_varwidth\ \\\n\ \ \ -variable\ WAITseconds\ \\\n\ \ \ -showvalue\ true\ \\\n\ \ \ -orient\ horizontal\ \\\n\ \ \ -bd\ \$BDwidthPx_scale\ \\\n\ \ \ -length\ \$initScaleLengthPx\ \\\n\ \ \ -width\ \$scaleThicknessPx\n\}\n##\ END\ OF\ if\ \{0\}\ de-activation\ of\ the\ scale\ widget.\n\n\n##\ Pack\ the\ widgets\ in\ frame\ '.fRbutton'.\n\npack\ .fRbuttons.buttEXIT\ \\\n\ \ \ \ \ .fRbuttons.buttHELP\ \\\n\ \ \ \ \ .fRbuttons.buttREFRESH\ \\\n\ \ \ -side\ left\ \\\n\ \ \ -anchor\ w\ \\\n\ \ \ -fill\ none\ \\\n\ \ \ -expand\ 0\n\n#\ \ \ \ \ .fRbuttons.labelSCALE\ \\\n#\ \ \ \ \ .fRbuttons.scaleSECONDS\ \\\n\n\n##+########################################################\n##\ In\ FRAME\ '.fRcanvases.fRcanvas1'\ -\n##\ DEFINE-and-PACK\ TWO\ LABELs\ and\n##\ ONE\ CANVAS\ WIDGET\ (no\ scrollbars).\n##\n##\ We\ highlightthickness\ &\ borderwidth\ of\ the\ canvas\ to\n##\ zero,\ as\ suggested\ on\ page\ 558,\ Chapter\ 37,\ 'The\ Canvas\n##\ Widget',\ in\ the\ 4th\ edition\ of\ the\ book\ 'Practical\n##\ Programming\ in\ Tcl\ and\ Tk'.\n##+#######################################################\n\nlabel\ .fRcanvases.fRcanvas1.labelINFO1\ \\\n\ \ \ -text\ \"\"\ \\\n\ \ \ -font\ fontTEMP_SMALL_varwidth\ \\\n\ \ \ -justify\ left\ \\\n\ \ \ -anchor\ w\ \\\n\ \ \ -relief\ flat\ \\\n\ \ \ -padx\ \$PADXpx_label\ \\\n\ \ \ -pady\ \$PADYpx_label\ \\\n\ \ \ -bd\ \$BDwidthPx_label\n\nlabel\ .fRcanvases.fRcanvas1.labelINFO2\ \\\n\ \ \ -text\ \"\"\ \\\n\ \ \ -font\ fontTEMP_SMALL_varwidth\ \\\n\ \ \ -justify\ left\ \\\n\ \ \ -anchor\ w\ \\\n\ \ \ -relief\ flat\ \\\n\ \ \ -padx\ \$PADXpx_label\ \\\n\ \ \ -pady\ \$PADYpx_label\ \\\n\ \ \ -bd\ \$BDwidthPx_label\n\ncanvas\ .fRcanvases.fRcanvas1.can\ \\\n\ \ \ -width\ \ \$initCanWidthPx\ \\\n\ \ \ -height\ \$initCanHeightPx\ \\\n\ \ \ -relief\ flat\ \\\n\ \ \ -highlightthickness\ 0\ \\\n\ \ \ -borderwidth\ 0\n\n##\ Pack\ the\ widgets\ in\ frame\ '.fRcanvases.fRcanvas1'.\n\npack\ .fRcanvases.fRcanvas1.labelINFO1\ \\\n\ \ \ \ \ .fRcanvases.fRcanvas1.labelINFO2\ \\\n\ \ \ -side\ top\ \\\n\ \ \ -anchor\ nw\ \\\n\ \ \ -fill\ x\ \\\n\ \ \ -expand\ 0\n\npack\ .fRcanvases.fRcanvas1.can\ \\\n\ \ \ -side\ top\ \\\n\ \ \ -anchor\ nw\ \\\n\ \ \ -fill\ none\ \\\n\ \ \ -expand\ 0\n\n\n##+########################################################\n##\ In\ FRAME\ '.fRcanvases.fRcanvas2'\ -\n##\ DEFINE-and-PACK\ TWO\ LABELs\ and\n##\ ONE\ CANVAS\ WIDGET\ (no\ scrollbars).\n##\n##\ We\ highlightthickness\ &\ borderwidth\ of\ the\ canvas\ to\n##\ zero,\ as\ suggested\ on\ page\ 558,\ Chapter\ 37,\ 'The\ Canvas\n##\ Widget',\ in\ the\ 4th\ edition\ of\ the\ book\ 'Practical\n##\ Programming\ in\ Tcl\ and\ Tk'.\n##+#######################################################\n\nlabel\ .fRcanvases.fRcanvas2.labelINFO1\ \\\n\ \ \ -text\ \"\"\ \\\n\ \ \ -font\ fontTEMP_SMALL_varwidth\ \\\n\ \ \ -justify\ left\ \\\n\ \ \ -anchor\ w\ \\\n\ \ \ -relief\ flat\ \\\n\ \ \ -padx\ \$PADXpx_label\ \\\n\ \ \ -pady\ \$PADYpx_label\ \\\n\ \ \ -bd\ \$BDwidthPx_label\n\nlabel\ .fRcanvases.fRcanvas2.labelINFO2\ \\\n\ \ \ -text\ \"\"\ \\\n\ \ \ -font\ fontTEMP_SMALL_varwidth\ \\\n\ \ \ -justify\ left\ \\\n\ \ \ -anchor\ w\ \\\n\ \ \ -relief\ flat\ \\\n\ \ \ -padx\ \$PADXpx_label\ \\\n\ \ \ -pady\ \$PADYpx_label\ \\\n\ \ \ -bd\ \$BDwidthPx_label\n\ncanvas\ .fRcanvases.fRcanvas2.can\ \\\n\ \ \ -width\ \ \$initCanWidthPx\ \\\n\ \ \ -height\ \$initCanHeightPx\ \\\n\ \ \ -relief\ flat\ \\\n\ \ \ -highlightthickness\ 0\ \\\n\ \ \ -borderwidth\ 0\n\n##\ Pack\ the\ widgets\ in\ frame\ '.fRcanvases.fRcanvas2'.\n\npack\ .fRcanvases.fRcanvas2.labelINFO1\ \\\n\ \ \ \ \ .fRcanvases.fRcanvas2.labelINFO2\ \\\n\ \ \ -side\ top\ \\\n\ \ \ -anchor\ nw\ \\\n\ \ \ -fill\ x\ \\\n\ \ \ -expand\ 0\n\npack\ .fRcanvases.fRcanvas2.can\ \\\n\ \ \ -side\ top\ \\\n\ \ \ -anchor\ nw\ \\\n\ \ \ -fill\ none\ \\\n\ \ \ -expand\ 0\n\n\n##+##################################################\n##\ END\ OF\ DEFINITION\ of\ the\ GUI\ widgets.\n##+##################################################\n##\ Start\ of\ BINDINGS,\ PROCS,\ Added-GUI-INIT\ sections.\n##+##################################################\n\n##+##################################################################\n##+##################################################################\n##\ \ BINDINGS\ SECTION:\ \ none\n##+##################################################################\n\n\n##+##################################################################\n##+##################################################################\n##\ DEFINE\ PROCS\ SECTION:\n##\n##\ \ \ \ 'make_tachometers'\ -\ to\ draw\ 2\ meters\ within\ 2\ Tk\ canvases\n##\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (We\ may\ allow\ the\ Tk\ canvases\ to\ resize\ according\ to\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ a\ resizing\ of\ the\ window.\ This\ proc\ will\ draw\ the\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 2\ meters\ in\ proportion\ to\ the\ size\ of\ their\ canvases.)\n##\n##\ \ \ \ 'make_one_tachometer'\ -\ to\ draw\ one\ tachometer.\ Called\ by\ 'make_tachometers'\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ to\ make\ the\ 2\ meters.\n##\n##\ \ \ \ 'draw_rivet'\ \ \ \ \ \ \ \ \ \ -\ called\ by\ 'make_tachometers'\ to\ put\ rivets\ in\ 4\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ corners\ around\ each\ meter.\n##\n##\ \ \ \ 'draw_circle_shadow'\ \ -\ called\ by\ 'make_tachometers'\ to\ put\ a\ shadowed\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ edge\ around\ the\ circle\ that\ makes\ each\ meter.\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Also\ called\ by\ 'make_tachometers'\ to\ put\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ a\ shadowed\ edge\ on\ the\ 'pin'\ that\ holds\ a\ needle.\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Also\ called\ by\ 'draw_rivet'\ to\ put\ a\ shadowed\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ edge\ on\ each\ rivet.\n##\n##\ \ \ \ 'update_needles'\ \ \ \ \ -\ to\ update\ the\ 2\ needles\ on\ the\ 2\ meters.\ Called\ in\ a\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ recursive\ loop,\ initiated\ at\ the\ bottom\ of\ this\ script.\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ And\ called\ in\ a\ 'Refresh'\ proc.\n##\n##\ \ \ 'update_one_needle'\ \ \ -\ to\ draw\ one\ needle\ in\ a\ specified\ canvas.\ Called\ by\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'update_needles'\ to\ update\ the\ 2\ needles\ on\ the\ 2\ meters.\n##\n##\ \ \ 'Refresh'\ \ \ \ \ \ \ \ \ \ \ \ \ -\ called\ by\ the\ 'Refresh'\ button.\ Runs\ the\ procs\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'make_tachometers'\ and\ 'update_needles'\ ---\ in\ particular,\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ the\ user\ to\ force\ the\ meters\ to\ be\ resized\ if\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ user\ resizes\ the\ window\ ---\ and\ whenever\ the\ user\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ wants\ a\ new\ 'reading'.\n##\n##\ 'popup_msgVarWithScroll'\ -\ to\ show\ the\ HELPtext\ var.\ Called\ by\ the\ 'Help'\ button.\n##\n##+#################################################################\n\n\n##+########################################################################\n##\ PROC\ 'make_tachometers'\n##+########################################################################\n##\ PURPOSE:\ Draws\ all\ features\ of\ 2\ tachometer-style\ meters\ (except\ the\n##\ \ \ \ \ \ \ \ \ \ needles)\ ---\ in\ a\ 'nice\ filling-size'\ according\ to\ the\n##\ \ \ \ \ \ \ \ \ \ current\ canvas\ dimensions.\n##\n##\ \ \ \ \ \ \ \ \ \ \ \ (We\ will\ allow\ the\ canvas\ to\ resize\ according\ to\n##\ \ \ \ \ \ \ \ \ \ \ \ \ a\ resizing\ of\ the\ window.\ This\ proc\ will\ redraw\ the\n##\ \ \ \ \ \ \ \ \ \ \ \ \ meters\ in\ proportion\ to\ the\ new\ size\ of\ the\ canvas.)\n##\n##\ CALLED\ BY:\ once,\ at\ the\ 'Additional\ GUI\ Initialization'\ section,\n##\ \ \ \ \ \ \ \ \ \ \ \ at\ the\ bottom\ of\ this\ script\ ---\ and\n##\ \ \ \ \ \ \ \ \ \ \ \ in\ the\ 'ReDraw...'\ proc.\n##+########################################################################\n\nproc\ make_tachometers\ \{\}\ \{\n\n\ \ \ global\ marginPx\n\n\ \ \ ##\ FOR\ TESTING:\ (to\ dummy\ out\ this\ proc)\n\ \ \ #\ \ return\n\n\ \ \ ############################################################\n\ \ \ ##\ Get\ current\ '.fRcanvases'\ dimensions\ ---\ in\ case\ the\ user\n\ \ \ ##\ has\ resized\ the\ window,\ and\ thus\ the\ '.fRcanvases'\ frame.\n\ \ \ ############################################################\n\ \n\ \ \ #\ set\ curCanvasesWidthPx\ \ \[.fRcanvases\ cget\ -width\]\n\ \ \ #\ set\ curCanvasesHeightPx\ \[.fRcanvases\ cget\ -height\]\n\n\ \ \ set\ curCanvasesWidthPx\ \ \[winfo\ width\ \ .fRcanvases\]\n\ \ \ set\ curCanvasesHeightPx\ \[winfo\ height\ .fRcanvases\]\n\n\n\ \ \ ############################################################\n\ \ \ ##\ Set\ a\ width-and-height\ to\ use\ for\ a\ canvas\n\ \ \ ##\ to\ contain\ each\ of\ the\ 2\ meters.\n\ \ \ ##\ (Half\ the\ 'fRcanvases'\ width.)\n\ \ \ ############################################################\n\n\ \ \ set\ canvasSizePx\ \[expr\ \{int((\$curCanvasesWidthPx\ -\ 8)\ /\ 2.0)\}\]\n\n\ \ \ if\ \{\$curCanvasesHeightPx\ <\ \$canvasSizePx\}\ \{set\ canvasSizePx\ \$curCanvasesHeightPx\}\n\n\ \ \ ####################################################################\n\ \ \ ##\ Resize\ the\ frames\ 'fRcanvas1'\ and\ 'fRcanvas2'\ that\n\ \ \ ##\ hold\ the\ 2\ (square)\ Tk\ canvases\ for\ the\ 2\ meters\n\ \ \ ##\ ---\ or\ resize\ the\ 2\ canvases,\ themselves.\n\ \ \ ####################################################################\n\n\ \ \ if\ \{0\}\ \{\n\ \ \ .fRcanvases.fRcanvas1\ configure\ -width\ \ \$canvasSizePx\n\ \ \ .fRcanvases.fRcanvas1\ configure\ -height\ \$canvasSizePx\n\ \ \ .fRcanvases.fRcanvas2\ configure\ -width\ \ \$canvasSizePx\n\ \ \ .fRcanvases.fRcanvas2\ configure\ -height\ \$canvasSizePx\n\ \ \ \}\n\n\ \ \ .fRcanvases.fRcanvas1.can\ configure\ -width\ \ \$canvasSizePx\n\ \ \ .fRcanvases.fRcanvas1.can\ configure\ -height\ \$canvasSizePx\n\ \ \ update\n\ \ \ .fRcanvases.fRcanvas2.can\ configure\ -width\ \ \$canvasSizePx\n\ \ \ .fRcanvases.fRcanvas2.can\ configure\ -height\ \$canvasSizePx\n\ \ \ update\n\n\ \ \ set\ doubleWidthPx\ \[expr\ \{(2\ *\ \$canvasSizePx)\ +\ 8\}\]\n\ \ \ .fRcanvases\ configure\ -width\ \ \$doubleWidthPx\n\ \ \ .fRcanvases\ configure\ -height\ \$canvasSizePx\n\ \ \ update\n\n\ \ \ #########################################################\n\ \ \ ##\ Draw\ meter1\ (without\ needle).\n\ \ \ #########################################################\n\n\ \ \ make_one_tachometer\ .fRcanvases.fRcanvas1.can\n\n\n\ \ \ #########################################################\n\ \ \ ##\ Draw\ meter2\ (without\ needle).\n\ \ \ #########################################################\n\n\ \ \ make_one_tachometer\ .fRcanvases.fRcanvas2.can\n\n\}\n##\ END\ OF\ proc\ 'make_tachometers'\n\n\n##+########################################################################\n##\ PROC\ 'make_one_tachometer'\n##+########################################################################\n##\ PURPOSE:\ Draws\ all\ features\ of\ a\ tachometer-style\ meter\ (except\ the\n##\ \ \ \ \ \ \ \ \ \ needle)\ ---\ according\ to\ the\ 'marginPx'\ parameter\ to\ set\n##\ \ \ \ \ \ \ \ \ \ top-right\ and\ bottom-left\ coordinates\ to\ specify\ the\ location\n##\ \ \ \ \ \ \ \ \ \ of\ the\ square\ exactly\ containing\ the\ circular\ meter\ on\n##\ \ \ \ \ \ \ \ \ \ the\ canvas\ whose\ ID\ is\ passed\ into\ this\ proc.\n##\n##\ \ The\ features\ include:\n##\ \ \ \ \ \ -\ white-filled\ circle\ for\ the\ meter\ background\n##\ \ \ \ \ \ -\ a\ gray-shaded\ (shadowed)\ edge\ around\ the\ circle\n##\ \ \ \ \ \ -\ a\ 'pin'\ in\ the\ center\ of\ the\ circle,\ for\ the\ needle\n##\ \ \ \ \ \ -\ 4\ decorative\ rivets\ at\ the\ corners\ of\ the\ canvas\n##\ \ \ \ \ \ -\ an\ arc\ with\ tic-marks\n##\ \ \ \ \ \ -\ a\ red\ danger-zone\ in\ the\ last\ segment\ of\ the\ arc\n##\ \ \ \ \ \ \ \ (between\ the\ last\ pair\ of\ tic-marks)\n##\ \ \ \ \ \ -\ labels\ for\ the\ tic-marks\n##\n##\ CALLED\ BY:\ proc\ 'make_tachometers'\n##+#######################################################################\n\n##\ Set\ an\ 'indentation'\ to\ use\ for\ placing\ the\ outer-circle\ of\ the\ 2\ meters\n##\ from\ the\ 4\ edges\ of\ their\ respective\ canvases.\n\nset\ marginPx\ 12\n\nset\ pi\ \[expr\ \{4.0\ *\ atan(1.0)\}\]\nset\ radsPERdeg\ \[expr\ \{\$pi/180.0\}\]\n\nset\ Nsegs\ 10\nset\ pcentLabels\ \"0\ 10\ 20\ 30\ 40\ 50\ 60\ 70\ 80\ 90\ 100\"\n\n##\ The\ above\ variables\ are\ set\ ONCE,\ for\ use\ in\ the\ following\ proc.\n\nproc\ make_one_tachometer\ \{canvas\}\ \{\n\n\ \ \ global\ marginPx\ pi\ radsPERdeg\ Nsegs\ pcentLabels\n\n\ \ \ ##\ FOR\ TESTING:\ (to\ dummy\ out\ this\ proc)\n\ \ \ #\ \ \ return\n\ \n\ \ \ ################################################################\n\ \ \ ##\ Remove\ any\ previously\ drawn\ elements\ in\ this\ canvas,\ if\ any.\n\ \ \ ################################################################\n\n\ \ \ catch\ \{\$canvas\ delete\ all\}\n\n\n\ \ \ ##################################################################\n\ \ \ ##\ Get\ the\ width\ (=\ height)\ of\ the\ specified\ (square)\ canvas.\n\ \ \ ##################################################################\n\n\ \ \ set\ curCanvasSizePx\ \ \[winfo\ width\ \ \$canvas\]\n\n\ \ \ ##################################################################\n\ \ \ ##\ Set\ the\ corner\ coords\ for\ drawing\ the\ meter\ circle\ (background).\n\ \ \ ##################################################################\n\n\ \ \ set\ topleftXpx\ \$marginPx\n\ \ \ set\ topleftYpx\ \$marginPx\n\ \ \ set\ botrightXpx\ \[expr\ \{\$curCanvasSizePx\ -\ \$marginPx\}\]\n\ \ \ set\ botrightYpx\ \[expr\ \{\$curCanvasSizePx\ -\ \$marginPx\}\]\n\n\n\ \ \ ################################################\n\ \ \ ##\ Draw\ basic\ white-filled\ circle\ for\ the\ meter.\n\ \ \ ################################################\n\n\ \ \ \$canvas\ create\ oval\ \\\n\ \ \ \ \ \ \$topleftXpx\ \$topleftYpx\ \$botrightXpx\ \$botrightYpx\ \\\n\ \ \ \ \ \ -fill\ white\ -outline\ \{\}\n\n\ \ \ #\ -width\ 1\ -outline\ lightgray\n\n\ \ \ ##\ FOR\ TESTING:\ (exit\ this\ proc\ before\ adding\ more\ to\ the\ meter)\n\ \ \ #\ \ \ return\n\n\n\ \ \ #######################################################################\n\ \ \ ##\ Draw\ shadow-circle\ at\ the\ outer\ circle\ of\ the\ meter.\n\ \ \ #######################################################################\n\ \ \ ##\ INPUTS:\n\ \ \ ##\ -\ the\ 4\ corner\ coordinates\ of\ the\ oval/circle\ box\ (in\ pixels)\n\ \ \ ##\ -\ number\ of\ segments\ for\ the\ arc\ (segments\ of\ differing\ color\ shade)\n\ \ \ ##\ -\ width\ (in\ pixels)\ to\ draw\ the\ arc\ segments\n\ \ \ ##\ -\ start\ angle\ for\ drawing\ the\ (darker)\ arc\ segments\n\ \ \ ##\ \ \ (measured\ counter-clockwise\ from\ the\ 3\ o'clock\ position)\n\ \ \ ##\ \ \ (An\ angle\ of\ +135=90+45\ means\ the\ dark\ side\ of\ the\ 'shadow-circle'\n\ \ \ ##\ \ \ \ is\ on\ the\ north-west\ side\ of\ the\ circle.)\n\ \ \ ######################################################################\n\n\ \ \ draw_circle_shadow\ \$canvas\ \\\n\ \ \ \ \ \ \$topleftXpx\ \$topleftYpx\ \$botrightXpx\ \$botrightYpx\ \\\n\ \ \ \ \ \ 40\ 6\ 135.0\n\ \n\ \ \ ##\ FOR\ TESTING:\ (exit\ this\ proc\ before\ adding\ more\ to\ the\ meter)\n\ \ \ #\ \ \ return\n\n\n\ \ \ ###################################################################\n\ \ \ ##\ Draw\ a\ shadow-circle\ for\ the\ 'pin'\ of\ the\ meter\ needle.\n\ \ \ ###################################################################\n\ \ \ ##\ INPUTS:\n\ \ \ ##\ -\ the\ 4\ corner\ coordinates\ of\ the\ oval/circle\ box\ (in\ pixels)\n\ \ \ ##\ -\ number\ of\ segments\ for\ the\ arc\ (segments\ of\ differing\ color\ shade)\n\ \ \ ##\ -\ width\ (in\ pixels)\ to\ draw\ the\ arc\ segments\n\ \ \ ##\ -\ start\ angle\ for\ drawing\ the\ (darker)\ arc\ segments\n\ \ \ ##\ \ \ \ (measured\ counter-clockwise\ from\ the\ 3\ o'clock\ position)\n\ \ \ ##\ \ \ \ (An\ angle\ of\ -45\ means\ the\ dark\ side\ of\ the\ 'shadow-circle'\n\ \ \ ##\ \ \ \ \ is\ on\ the\ south-east\ side\ of\ the\ circle.)\n\ \ \ ###################################################################\n\n\ \ \ set\ centerXpx\ \[expr\ \{int(\$curCanvasSizePx/2.0)\}\]\n\ \ \ set\ centerYpx\ \$centerXpx\n\n\ \ \ set\ pinOuterRadiusPx\ 14\n\n\ \ \ set\ x1\ \[expr\ \{\$centerXpx\ -\ \$pinOuterRadiusPx\}\]\n\ \ \ set\ y1\ \[expr\ \{\$centerYpx\ -\ \$pinOuterRadiusPx\}\]\n\ \ \ set\ x2\ \[expr\ \{\$centerXpx\ +\ \$pinOuterRadiusPx\}\]\n\ \ \ set\ y2\ \[expr\ \{\$centerYpx\ +\ \$pinOuterRadiusPx\}\]\n\n\ \ \ draw_circle_shadow\ \$canvas\ \$x1\ \$y1\ \$x2\ \$y2\ 40\ 6\ -45.0\n\n\ \ \ ##\ FOR\ TESTING:\ (exit\ this\ proc\ before\ adding\ more\ to\ the\ meter)\n\ \ \ #\ \ \ return\n\n\n\ \ \ ############################################################\n\ \ \ ##\ Draw\ a\ red-filled\ circle\ on\ the\ 'pin'\ of\ the\ meter\ needle.\n\ \ \ ############################################################\n\n\ \ \ set\ pinRadiusPx\ 12\n\n\ \ \ set\ x1\ \[expr\ \{\$centerXpx\ -\ \$pinRadiusPx\}\]\n\ \ \ set\ y1\ \[expr\ \{\$centerYpx\ -\ \$pinRadiusPx\}\]\n\ \ \ set\ x2\ \[expr\ \{\$centerXpx\ +\ \$pinRadiusPx\}\]\n\ \ \ set\ y2\ \[expr\ \{\$centerYpx\ +\ \$pinRadiusPx\}\]\n\n\ \ \ \$canvas\ create\ oval\ \\\n\ \ \ \ \ \ \$x1\ \$y1\ \$x2\ \$y2\ -fill\ red\ -outline\ \{\}\n\n\ \ \ #\ \ \ -width\ 1\ -outline\ lightgray\n\n\ \ \ ##\ FOR\ TESTING:\ (exit\ this\ proc\ before\ adding\ more\ to\ the\ meter)\n\ \ \ #\ \ \ return\n\n\n\ \ \ ###########################################\n\ \ \ ##\ Draw\ arc-line\ on\ which\ to\ put\ tic\ marks.\n\ \ \ #################################################\n\ \ \ ##\ 320\ degrees\ counter-clockwise\ from\ -70\ degrees\n\ \ \ ##\ (based\ at\ 3\ oclock)\ is\ 70\ degrees\ beyond\ 180.\n\ \ \ ##\ I.e.\ -70\ +\ 320\ =\ 250\ =\ 180\ +\ 70\n\ \ \ #################################################\n\n\ \ \ set\ arcLineIndentPx\ 10\n\n\ \ \ set\ x1\ \[expr\ \{\$topleftXpx\ \ +\ \$arcLineIndentPx\}\]\n\ \ \ set\ y1\ \[expr\ \{\$topleftYpx\ \ +\ \$arcLineIndentPx\}\]\n\ \ \ set\ x2\ \[expr\ \{\$botrightXpx\ -\ \$arcLineIndentPx\}\]\n\ \ \ set\ y2\ \[expr\ \{\$botrightYpx\ -\ \$arcLineIndentPx\}\]\n\n\ \ \ \$canvas\ create\ arc\ \$x1\ \$y1\ \$x2\ \$y2\ \\\n\ \ \ \ \ \ -start\ -70\ -extent\ 320\ -style\ arc\ \\\n\ \ \ \ \ \ -outline\ black\ -width\ 2\n\n\ \ \ ##\ FOR\ TESTING:\ (exit\ this\ proc\ before\ adding\ more\ to\ the\ meter)\n\ \ \ #\ \ \ return\n\n\n\ \ \ ##################################################\n\ \ \ ##\ Draw\ tic-marks\ and\ labels\ around\ the\ meter.\n\ \ \ ##################################################\n\n\ \ \ set\ DEGperTIC\ \[expr\ \{320.0/\$Nsegs\}\]\n\ \ \ set\ half\ \ \$centerXpx\n\n\ \ \ ##\ \ outer\ location\ (radius)\ of\ tic\ marks\n\ \ \ set\ l1\ \ \ \ \[expr\ \{\$half\ -\ (\$arcLineIndentPx\ +\ \$marginPx)\}\]\n\n\ \ \ ##\ \ inner\ location\ (radius)\ of\ tic\ marks\n\ \ \ set\ l2\ \ \ \ \[expr\ \{\$l1\ -\ \$arcLineIndentPx\}\]\n\n\ \ \ ##\ inner\ location\ of\ tic\ labels\n\ \ \ set\ l3\ \ \ \ \[expr\ \{\$l2\ -\ \$arcLineIndentPx\}\]\n\ \n\ \ \ set\ angle0\ \ 250.0\n\n\ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <=\ \$Nsegs\}\ \{incr\ i\}\ \{\n\n\ \ \ \ \ \ set\ rads\ \[expr\ \{(\$angle0\ -\ (\$DEGperTIC\ *\ \$i))\ *\ \$radsPERdeg\}\]\n\ \n\ \ \ \ \ \ set\ x1\ \[expr\ \{\$half\ +\ \$l1\ *\ cos(\$rads)\}\]\n\ \ \ \ \ \ set\ y1\ \[expr\ \{\$half\ -\ \$l1\ *\ sin(\$rads)\}\]\n\ \ \ \ \ \ set\ x2\ \[expr\ \{\$half\ +\ \$l2\ *\ cos(\$rads)\}\]\n\ \ \ \ \ \ set\ y2\ \[expr\ \{\$half\ -\ \$l2\ *\ sin(\$rads)\}\]\n\n\ \ \ \ \ \ \$canvas\ \ create\ line\ \\\n\ \ \ \ \ \ \ \ \ \$x1\ \$y1\ \$x2\ \$y2\ \\\n\ \ \ \ \ \ \ \ \ -fill\ black\ -width\ 2\n\ \n\ \ \ \ \ \ set\ x1\ \[expr\ \{\$half\ +\ \$l3\ *\ cos(\$rads)\}\]\n\ \ \ \ \ \ set\ y1\ \[expr\ \{\$half\ -\ \$l3\ *\ sin(\$rads)\}\]\n\ \n\ \ \ \ \ \ set\ label\ \[lindex\ \$pcentLabels\ \$i\]\n\n\ \ \ \ \ \ if\ \{\ \[string\ length\ \$label\]\ \}\ \{\n\ \ \ \ \ \ \ \ \ \$canvas\ create\ text\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$x1\ \$y1\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -anchor\ center\ -justify\ center\ -fill\ black\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -text\ \$label\ -font\ \{\ Helvetica\ 10\ \}\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ ##\ END\ OF\ labels\ loop.\n\n\ \ \ \}\n\ \ \ ##\ END\ OF\ i-loop\ for\ tic-marks\n\n\ \ \ ##\ FOR\ TESTING:\ (exit\ this\ proc\ before\ adding\ more\ to\ the\ meter)\n\ \ \ #\ \ \ return\n\n\n\ \ \ #######################################################\n\ \ \ ##\ Draw\ red-line\ arc-segment\ (danger\ zone)\ of\ the\ meter.\n\ \ \ #######################################################\n\n\ \ \ set\ redLineIndentPx\ 15\n\n\ \ \ set\ x1\ \[expr\ \{\$topleftXpx\ \ +\ \$redLineIndentPx\}\]\n\ \ \ set\ y1\ \[expr\ \{\$topleftYpx\ \ +\ \$redLineIndentPx\}\]\n\ \ \ set\ x2\ \[expr\ \{\$botrightXpx\ -\ \$redLineIndentPx\}\]\n\ \ \ set\ y2\ \[expr\ \{\$botrightYpx\ -\ \$redLineIndentPx\}\]\n\n\ \ \ \$canvas\ create\ arc\ \$x1\ \$y1\ \$x2\ \$y2\ \\\n\ \ \ \ \ \ -start\ -70\ -extent\ \$DEGperTIC\ -style\ arc\ \\\n\ \ \ \ \ \ -outline\ red\ -fill\ red\ -width\ 8\n\n\ \ \ ##\ FOR\ TESTING:\ (exit\ this\ proc\ before\ adding\ more\ to\ the\ meter)\n\ \ \ #\ \ \ return\n\n\n\ \ \ ##################################\n\ \ \ ##\ Draw\ 4\ rivets\ around\ the\ meter.\n\ \ \ ##################################\n\n\ \ \ set\ RIVETindentPx\ 10\n\ \ \ set\ RIVEToutdentPx\ \[expr\ \{\$curCanvasSizePx\ -\ \$RIVETindentPx\}\]\n\n\ \ \ ##\ upper-left\ rivet\n\ \ \ draw_rivet\ \$canvas\ \$RIVETindentPx\ \$RIVETindentPx\n\ \ \ ##\ upper-right\ rivet\n\ \ \ draw_rivet\ \$canvas\ \$RIVEToutdentPx\ \$RIVETindentPx\n\ \ \ ##\ lower-left\ rivet\n\ \ \ draw_rivet\ \$canvas\ \$RIVETindentPx\ \$RIVEToutdentPx\n\ \ \ ##\ lower-right\ rivet\n\ \ \ draw_rivet\ \$canvas\ \$RIVEToutdentPx\ \$RIVEToutdentPx\n\n\ \n\}\n##\ END\ OF\ proc\ 'make_tachometers'\n\n\n##+########################################################################\n##\ PROC\ 'draw_rivet'\n##+########################################################################\n##\ PURPOSE:\ Put\ a\ rivet\ at\ a\ specified\ center\ point.\n##\ \ \ \ \ \ \ \ \ \ The\ center\ point\ is\ specified\ in\ pixels,\ as\ a\ location\ on\n##\ \ \ \ \ \ \ \ \ \ the\ canvas\ of\ the\ GUI,\ relative\ to\ the\ upper\ left\ corner.\n##\n##\ \ \ \ \ \ \ \ \ \ (We\ pass\ the\ radius\ of\ the\ rivets\ in\ a\ global\ variable.)\n##\n##\ CALLED\ BY:\ the\ 'make_tachometer'\ proc\n##+########################################################################\n\nset\ rivetRadiusPx\ 4\n\nproc\ draw_rivet\ \{\ canvas\ centerXpx\ centerYpx\ \}\ \{\n\n\ \ \ global\ rivetRadiusPx\n\n\ \ \ ##\ FOR\ TESTING:\n\ \ \ #\ \ \ return\n\n\ \ \ ########################################################\n\ \ \ ##\ Draw\ a\ color\ shaded\ arc\ using\n\ \ \ ##\ -\ 5\ arc\ segments\ around\ each\ half\ of\ the\ circle/oval\n\ \ \ ##\ -\ 3\ pixels\ for\ width\ of\ the\ arc\ segments\n\ \ \ ##\ -\ -45\ degrees\ for\ the\ start\ angle\ (darkest\ shade)\n\ \ \ ########################################################\n\n\ \ \ draw_circle_shadow\ \$canvas\ \\\n\ \ \ \ \ \ \[expr\ \{\$centerXpx\ -\ \$rivetRadiusPx\}\]\ \\\n\ \ \ \ \ \ \[expr\ \{\$centerYpx\ -\ \$rivetRadiusPx\}\]\ \\\n\ \ \ \ \ \ \[expr\ \{\$centerXpx\ +\ \$rivetRadiusPx\}\]\ \\\n\ \ \ \ \ \ \[expr\ \{\$centerYpx\ +\ \$rivetRadiusPx\}\]\ \\\n\ \ \ \ \ \ 5\ 3\ -45.0\n\n\}\n##\ END\ OF\ proc\ 'draw_rivet'\n\n\n##+########################################################################\n##\ PROC\ 'draw_circle_shadow'\n##+########################################################################\n##\ PURPOSE:\ Puts\ a\ shadowed\ edge\ around\ an\ oval/circle\ in\ a\ specified\ 'box'.\n##\ \ \ \ \ \ \ \ \ \ \n##\ INPUTS:\ -\ the\ corner\ coordinates\ of\ the\ oval/circle\ box\ (in\ pixels)\n##\ \ \ \ \ \ \ \ \ -\ number\ of\ segments\ for\ the\ arc\ (segments\ of\ differing\ color\ shade)\n##\ \ \ \ \ \ \ \ \ -\ width\ (in\ pixels)\ to\ draw\ the\ arc\ segments\n##\ \ \ \ \ \ \ \ \ -\ start\ angle\ for\ drawing\ the\ arc\ segments\n##\n##\ CALLED\ BY:\ the\ 'make_tachometers'\ and\ 'draw_rivets'\ procs\n##+########################################################################\n\nproc\ draw_circle_shadow\ \{canvas\ x1\ y1\ x2\ y2\ Nsegs\ ARCwidthPx\ startDEGREES\ \}\ \{\n\n\ \ \ ##\ FOR\ TESTING:\ (dummy\ out\ this\ proc)\n\ \ \ #\ \ \ return\n\n\ \ \ set\ DEGperSHADE\ \[expr\ \{180.0/\$Nsegs\}\]\n\n\ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <=\ \$Nsegs\}\ \{incr\ i\}\ \{\n\n\ \ \ \ \ \ set\ a\ \[expr\ \{(\$startDEGREES\ +\ \$i\ *\ \$DEGperSHADE)\}\]\n\ \ \ \ \ \ set\ b\ \[expr\ \{(\$startDEGREES\ -\ \$i\ *\ \$DEGperSHADE)\}\]\n\ \n\ \ \ \ \ \ ##\ Make\ darker\ grays\ for\ greater\ angles.\n\ \ \ \ \ \ set\ color255\ \[expr\ \{40\ +\ \$i*(200/\$Nsegs)\}\]\n\ \ \ \ \ \ set\ hexcolor\ \[format\ \"#%x%x%x\"\ \$color255\ \$color255\ \$color255\]\n\ \n\ \ \ \ \ \ \$canvas\ create\ arc\ \\\n\ \ \ \ \ \ \ \ \ \$x1\ \$y1\ \$x2\ \$y2\ \\\n\ \ \ \ \ \ \ \ \ -start\ \$a\ -extent\ \$DEGperSHADE\ \\\n\ \ \ \ \ \ \ \ \ -style\ arc\ -outline\ \$hexcolor\ -width\ \$ARCwidthPx\n\n\ \ \ \ \ \ \$canvas\ create\ arc\ \\\n\ \ \ \ \ \ \ \ \ \$x1\ \$y1\ \$x2\ \$y2\ \\\n\ \ \ \ \ \ \ \ \ -start\ \$b\ -extent\ \$DEGperSHADE\ \\\n\ \ \ \ \ \ \ \ \ -style\ arc\ -outline\ \$hexcolor\ -width\ \$ARCwidthPx\n\n\ \ \ \ \ \ ##\ FOR\ TESTING:\ \ (show\ each\ pair\ of\ segments\ before\n\ \ \ \ \ \ ##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ drawing\ the\ next\ pair)\n\ \ \ \ \ \ #\ update\n\n\ \ \ \}\n\ \ \ ##\ END\ OF\ loop\ over\ the\ arc\ segments\n\n\}\n##\ END\ OF\ proc\ 'draw_circle_shadow'\n\n\n\n##+########################################################################\n##\ PROC\ 'update_needles'\n##+########################################################################\n##\ PURPOSE:\ Updates\ the\ a\ needle\ on\ a\ square\ canvas\ ---\ using\ the\n##\ \ \ \ \ \ \ \ \ \ Linux/Unix/BSD/Mac\ 'free'\ command\ to\ get\ \n##\ \ \ \ \ \ \ \ \ \ MEMtot,\ MEMused,\ SWAPtot,\ SWAPused\ (in\ Megabytes).\n##\n##\ \ \ \ \ \ \ \ \ \ Input\ is\ the\ canvas\ ID.\ This\ proc\ queries\ the\ canvas\ to\n##\ \ \ \ \ \ \ \ \ \ get\ its\ center\ and\ to\ determine\ an\ appropriate\ length\ for\n##\ \ \ \ \ \ \ \ \ \ the\ needle.\n##\n##\ CALLED\ BY:\ the\ 'Additional\ GUI\ Initialization'\ section\ at\ the\n##\ \ \ \ \ \ \ \ \ \ \ \ bottom\ of\ this\ script,\ in\ a\ 'while'\ loop.\n##+########################################################################\n\ \nproc\ update_needles\ \{\}\ \{\n\n\ \ \ global\ argv0\n\ \ \ #\ global\ env\n\n\ \ \ ##########################################################\n\ \ \ ##\ Get\ the\ directory\ that\ this\ Tk\ script\ is\ in.\ That\ should\n\ \ \ ##\ be\ the\ directory\ that\ the\ utility\ shell\ script\ is\ in\n\ \ \ ##\ ---\ to\ get\ the\ memory\ and\ swap\ data\ values.\n\ \ \ ##########################################################\n\n\ \ \ ##\ FOR\ TESTING:\n\ \ \ #\ \ puts\ \"argv0:\ \$argv0\"\n\n\ \ \ #\ set\ thisDIR\ \".\"\n\ \ \ #\ set\ thisDIR\ \"\[pwd\]\"\n\ \ \ #\ set\ thisDIR\ \"\$env(HOME)/apps/tkUtils\"\n\ \ \ \ \ set\ thisDIR\ \"\[file\ dirname\ \$argv0\]\"\n\n\ \ \ ##########################################################\n\ \ \ ##\ Get\ MEMtot,MEMused,SWAPtot,SWAPused\ via\ 'free'\ command.\n\ \ \ ##########################################################\n\n\ \ \ foreach\ \{MEMtot\ MEMused\ SWAPtot\ SWAPused\}\ \\\n\ \ \ \ \ \ \[exec\ \$thisDIR/get_memory_and_swap.sh\]\ \{break\}\n\n\ \ \ ##\ FOR\ TESTING:\n\ \ \ #\ \ \ puts\ \"\ MEMtot:\ \$MEMtot\ \ \ \ \ \ MEMused:\ \$MEMused\"\n\ \ \ #\ \ \ puts\ \"SWAPtot:\ \$SWAPtot\ \ \ \ SWAPused:\ \$SWAPused\"\n\n\ \ \ #########################################################\n\ \ \ ##\ Update\ the\ 2\ needles.\n\ \ \ #########################################################\n\n\ \ \ ##\ FOR\ TESTING:\ (hardcoded\ meter\ values)\n\ \ \ #\ update_one_needle\ .fRcanvases.fRcanvas1\ 2000\ 650\ Memory\n\ \ \ #\ update_one_needle\ .fRcanvases.fRcanvas2\ 1000\ 0\ Swap\n\n\ \ \ update_one_needle\ .fRcanvases.fRcanvas1\ \$MEMtot\ \$MEMused\ Memory\n\n\ \ \ update_one_needle\ .fRcanvases.fRcanvas2\ \$SWAPtot\ \$SWAPused\ Swap\n\n\ \ \ ############################################################\n\ \ \ ##\ Force\ the\ needles\ to\ show\ up\ on\ the\ GUI.\ (???)\n\ \ \ ##\ (This\ may\ be\ needed\ because\ this\ proc\ is\ being\ called\n\ \ \ ##\ \ in\ a\ 'while'\ loop\ at\ the\ bottom\ of\ this\ script.\ We\n\ \ \ ##\ \ do\ not\ 'fall\ into'\ the\ normal\ Tk\ event\ handling\ loop.)\n\ \ \ ############################################################\n\n\ \ \ update\n\n\}\n##\ END\ OF\ proc\ 'update_needles'\n\n\n##+########################################################################\n##\ PROC\ 'update_one_needle'\n##+########################################################################\n##\ PURPOSE:\ Updates\ the\ a\ needle\ on\ a\ square\ canvas\ ---\ using\ the\n##\ \ \ \ \ \ \ \ \ \ canvas\ ID\ and\ the\ tot\ and\ used\ numbers\ passed\ as\ arguments.\n##\n##\ \ \ \ \ \ \ \ \ \ Input\ is\ the\ canvas\ ID.\ This\ proc\ queries\ the\ canvas\ to\n##\ \ \ \ \ \ \ \ \ \ get\ its\ center\ and\ to\ determine\ an\ appropriate\ length\ for\n##\ \ \ \ \ \ \ \ \ \ the\ needle\ as\ a\ proportion\ of\ the\ (square)\ canvas\ size.\n##\n##\ CALLED\ BY:\ the\ 'Additional\ GUI\ Initialization'\ section\ at\ the\n##\ \ \ \ \ \ \ \ \ \ \ \ bottom\ of\ this\ script,\ in\ a\ 'while'\ loop.\n##+########################################################################\n\ \nproc\ update_one_needle\ \{frame\ TOT\ USED\ TYPE\}\ \{\n\n\ \ \ global\ pi\ radsPERdeg\ Nsegs\n\n\ \ \ ##\ FOR\ TESTING:\ (dummy\ out\ this\ routine)\n\ \ \ #\ \ return\n\n\ \ \ set\ PERcent\ \ \[expr\ \{(\$USED\ \ *\ 100.0)\ /\ \ \$TOT\}\]\n\n\ \ \ set\ TOTtext\ \"Total\ \$TYPE\ =\ \$TOT\ Megabytes\"\n\ \ \ set\ USEDtext\ \"Used\ \$TYPE\ =\ \$USED\ Megabytes\"\n\n\ \ \ \$frame.labelINFO1\ configure\ -text\ \"\$TOTtext\"\n\ \ \ \$frame.labelINFO2\ configure\ -text\ \"\$USEDtext\"\n\n\ \ \ ##\ Set\ the\ angle\ for\ the\ zero-point\ on\ the\ arc-of-tic-marks.\n\n\ \ \ set\ angle0\ \ 250.0\n\n\ \ \ ##\ Convert\ PERcent\ to\ an\ angle\ in\ radians\ on\ the\ arc.\n\n\ \ \ set\ degs\ \[expr\ \{\$angle0\ -\ (320.0\ *\ \$PERcent\ /\ 100.0)\}\]\n\ \ \ set\ rads\ \[expr\ \{\$degs\ *\ \$radsPERdeg\}\]\n\n\ \ \ ##\ FOR\ TESTING:\n\ \ \ #\ \ \ puts\ \"PERcent:\ \$PERcent\ \ \ degs:\ \$degs\ \ rads:\ \$rads\"\n\n\ \ \ ##\ Get\ the\ coord(s)\ of\ the\ center\ of\ the\ (square)\ canvas\n\ \ \ ##\ and\ calculate\ a\ length\ of\ the\ needle.\n\n\ \ \ #\ set\ width\ \ \[\$frame.can\ cget\ -width\]\n\ \ \ set\ width\ \ \[winfo\ width\ \$frame.can\]\n\ \ \ set\ half\ \ \ \[expr\ \{int(\$width\ /\ 2.0)\}\]\n\ \ \ set\ length\ \[expr\ \{int(\$half\ *\ 0.5)\}\]\n\n\ \ \ ##\ Calculate\ the\ coordinates\ for\ the\ tip\ and\ base\ of\ the\ needle.\n\ \n\ \ \ set\ xtip\ \[expr\ \{\$half\ +\ \$length*cos(\$rads)\}\]\n\ \ \ set\ ytip\ \[expr\ \{\$half\ -\ \$length*sin(\$rads)\}\]\n\ \n\ \ \ #\ set\ xbase\ \[expr\ \{\$half\ +\ 0.2*\$length*cos(\$rads)\}\]\n\ \ \ #\ set\ ybase\ \[expr\ \{\$half\ -\ 0.2*\$length*sin(\$rads)\}\]\n\n\ \ \ set\ xbase\ \$half\n\ \ \ set\ ybase\ \$half\n\ \n\ \ \ ##\ Remove\ a\ previous\ needle,\ if\ any.\n\n\ \ \ catch\ \{\$frame.can\ delete\ -tags\ TAGneedle\}\n\n\ \ \ ##\ Draw\ a\ red-line\ needle\ and\ a\ reddish-white\ line\ on\ either\ side\n\ \ \ ##\ ---\ for\ an\ (attempted)\ anti-aliasing\ effect.\n\n\ \ \ \$frame.can\ create\ line\ \\\n\ \ \ \ \ \ \$xbase\ \$ybase\ \$xtip\ \$ytip\ \\\n\ \ \ \ \ \ -fill\ #ff0000\ -width\ 4\ -tag\ TAGneedle\n\n\ \ \ \$frame.can\ create\ line\ \\\n\ \ \ \ \ \ \[expr\ \{\$xbase\ +\ 1\}\]\ \[expr\ \{\$ybase\ +\ 1\}\]\ \\\n\ \ \ \ \ \ \[expr\ \{\$xtip\ +\ 1\}\]\ \ \[expr\ \{\$ytip\ +\ 1\}\]\ \\\n\ \ \ \ \ \ -fill\ #ff8888\ -width\ 2\ -tag\ TAGneedle\n\n\ \ \ \$frame.can\ create\ line\ \\\n\ \ \ \ \ \ \[expr\ \{\$xbase\ -\ 1\}\]\ \[expr\ \{\$ybase\ -\ 1\}\]\ \\\n\ \ \ \ \ \ \[expr\ \{\$xtip\ -\ 1\}\]\ \ \[expr\ \{\$ytip\ -\ 1\}\]\ \\\n\ \ \ \ \ \ -fill\ #ff8888\ -width\ 2\ -tag\ TAGneedle\n\n\}\n##\ END\ OF\ proc\ 'update_one_needle'\n\n\n\n##+#############################################################\n##\ proc\ Refresh\n##\n##\ PURPOSE:\ 'Refresh'\ the\ two\ meters\ and\ their\ needles\ ---\n##\ \ \ \ \ \ \ \ \ \ \ for\ when\ the\ user\ wants\ a\ new\ set\ of\ values\n##\ \ \ \ \ \ \ \ \ \ \ and/or\ when\ the\ user\ resizes\ the\ window.\n##\n##\ CALLED\ BY:\ 'Refresh'\ button\n##+#############################################################\n\nproc\ Refresh\ \{\}\ \{\n\n\ \ \ make_tachometers\n\ \ \ update_needles\n\n\}\n##\ END\ OF\ proc\ 'Refresh'\n\n\n##+#############################################################\n##\ proc\ ReDraw_if_canvases_resized\n##\n##\ PURPOSE:\ To\ handle\ resizing\ the\ meters\ when\ the\ window\ is\n##\ \ \ \ \ \ \ \ \ \ resized\ ---\ IF\ the\ <Configure>\ binding\ is\ implemented.\n##\n##\ \ \ \ \ \ \ \ \ \ The\ intent\ is\ to\ avoid\ too\ many\ redraws\ ---\ for\n##\ \ \ \ \ \ \ \ \ \ almost\ every\ little\ resize\ of\ the\ window\ as\ its\n##\ \ \ \ \ \ \ \ \ \ border(s)\ are\ dragged.\n##\n##\ CALLED\ BY:\ bind\ .fRcanvas.can\ <Configure>\ \n##\ \ \ \ \ \ \ \ \ \ \ \ at\ bottom\ of\ this\ script.\n##+#############################################################\n##\ NOT\ IMPLEMENTED.\n##\ Code\ is\ included\ for\ possible\ future\ development.\n##+#############################################################\n\nproc\ ReDraw_if_canvases_resized\ \{\}\ \{\n\n\ \ \ global\ \ PREVcanvasesWidthPx\ PREVcanvasesHeightPx\ draw_wait0or1\n\n\ \ \ ##\ FOR\ TESTING:\ (to\ dummy\ out\ this\ proc)\n\ \ \ #\ \ return\n\n\ \ \ if\ \{\$draw_wait0or1\ ==\ 1\}\ \{return\}\n\n\ \ \ ##\ Set\ the\ wait\ indicator\ and\ delay\ doing\ the\ canvas\ resize\n\ \ \ ##\ check\ for\ about\ 300\ milliseconds\ ---\ to\ allow\ time\ for\ the\n\ \ \ ##\ user\ to\ stop\ moving\ the\ window.\ After\ about\ 300\ milliseconds,\n\ \ \ ##\ it\ is\ unlikely\ that\ the\ window\ is\ moving\ and\ thus\ causing\n\ \ \ ##\ multiple\ redraws.\n\n\ \ \ set\ draw_wait0or1\ 1\n\ \ \ after\ 900\n\n\ \ \ set\ CURcanvasesWidthPx\ \ \[winfo\ width\ \ .fRcanvases\]\n\ \ \ set\ CURcanvasesHeightPx\ \[winfo\ height\ .fRcanvases\]\n\n\ \ \ if\ \{\ \$CURcanvasesWidthPx\ \ !=\ \$PREVcanvasesWidthPx\ ||\ \\\n\ \ \ \ \ \ \ \ \$CURcanvasesHeightPx\ !=\ \$PREVcanvasesHeightPx\}\ \{\n\n\ \ \ \ \ \ make_tachometers\n\ \ \ \ \ \ update_needles\n\n\ \ \ \ \ \ set\ PREVcanvasesWidthPx\ \ \$CURcanvasesWidthPx\n\ \ \ \ \ \ set\ PREVcanvasesHeightPx\ \$CURcanvasesHeightPx\n\ \ \ \ \ \ set\ draw_wait0or1\ 0\n\ \ \ \}\n\n\}\n##\ END\ OF\ proc\ 'ReDraw_if_canvases_resized'\n\n\n##+########################################################################\n##\ PROC\ 'popup_msgVarWithScroll'\n##+########################################################################\n##\ PURPOSE:\ Report\ help\ or\ error\ conditions\ to\ the\ user.\n##\n##\ \ \ \ \ \ \ We\ do\ not\ use\ focus,grab,tkwait\ in\ this\ proc,\n##\ \ \ \ \ \ \ because\ we\ use\ it\ to\ show\ help\ when\ the\ GUI\ is\ idle,\n##\ \ \ \ \ \ \ and\ we\ may\ want\ the\ user\ to\ be\ able\ to\ keep\ the\ Help\n##\ \ \ \ \ \ \ window\ open\ while\ doing\ some\ other\ things\ with\ the\ GUI\n##\ \ \ \ \ \ \ such\ as\ putting\ a\ filename\ in\ the\ filename\ entry\ field\n##\ \ \ \ \ \ \ or\ clicking\ on\ a\ radiobutton.\n##\n##\ \ \ \ \ \ \ For\ a\ similar\ proc\ with\ focus-grab-tkwait\ added,\n##\ \ \ \ \ \ \ see\ the\ proc\ 'popup_msgVarWithScroll_wait'\ in\ a\n##\ \ \ \ \ \ \ 3DterrainGeneratorExaminer\ Tk\ script.\n##\n##\ REFERENCE:\ page\ 602\ of\ 'Practical\ Programming\ in\ Tcl\ and\ Tk',\n##\ \ \ \ \ \ \ \ \ \ \ \ 4th\ edition,\ by\ Welch,\ Jones,\ Hobbs.\n##\n##\ ARGUMENTS:\ A\ toplevel\ frame\ name\ (such\ as\ .fRhelp\ or\ .fRerrmsg)\n##\ \ \ \ \ \ \ \ \ \ \ \ and\ a\ variable\ holding\ text\ (many\ lines,\ if\ needed).\n##\n##\ CALLED\ BY:\ 'help'\ button\n##+########################################################################\n##\ To\ have\ more\ control\ over\ the\ formatting\ of\ the\ message\ (esp.\n##\ words\ per\ line),\ we\ use\ this\ 'toplevel-text'\ method,\ \n##\ rather\ than\ the\ 'tk_dialog'\ method\ --\ like\ on\ page\ 574\ of\ the\ book\ \n##\ by\ Hattie\ Schroeder\ &\ Mike\ Doyel,'Interactive\ Web\ Applications\n##\ with\ Tcl/Tk',\ Appendix\ A\ \"ED,\ the\ Tcl\ Code\ Editor\".\n##+########################################################################\n\nproc\ popup_msgVarWithScroll\ \{\ toplevName\ VARtext\ \}\ \{\n\n\ \ \ ##\ global\ fontTEMP_varwidth\ #\;\ Not\ needed.\ 'wish'\ makes\ this\ global.\n\ \ \ ##\ global\ env\n\n\ \ \ #\ bell\n\ \ \ #\ bell\n\ \ \n\ \ \ #################################################\n\ \ \ ##\ Set\ VARwidth\ &\ VARheight\ from\ \$VARtext.\n\ \ \ #################################################\n\ \ \ ##\ To\ get\ VARheight,\n\ \ \ ##\ \ \ \ split\ at\ '\\n'\ (newlines)\ and\ count\ 'lines'.\n\ \ \ #################################################\n\ \n\ \ \ set\ VARlist\ \[\ split\ \$VARtext\ \"\\n\"\ \]\n\n\ \ \ ##\ For\ testing:\n\ \ \ #\ \ puts\ \"VARlist:\ \$VARlist\"\n\n\ \ \ set\ VARheight\ \[\ llength\ \$VARlist\ \]\n\n\ \ \ ##\ For\ testing:\n\ \ \ #\ \ puts\ \"VARheight:\ \$VARheight\"\n\n\n\ \ \ #################################################\n\ \ \ ##\ To\ get\ VARwidth,\n\ \ \ ##\ \ \ \ loop\ through\ the\ 'lines'\ getting\ length\n\ \ \ ##\ \ \ \ \ of\ each\;\ save\ max.\n\ \ \ #################################################\n\n\ \ \ set\ VARwidth\ 0\n\n\ \ \ #############################################\n\ \ \ ##\ LOOK\ AT\ EACH\ LINE\ IN\ THE\ LIST.\n\ \ \ #############################################\n\ \ \ foreach\ line\ \$VARlist\ \{\n\n\ \ \ \ \ \ #############################################\n\ \ \ \ \ \ ##\ Get\ the\ length\ of\ the\ line.\n\ \ \ \ \ \ #############################################\n\ \ \ \ \ \ set\ LINEwidth\ \[\ string\ length\ \$line\ \]\n\n\ \ \ \ \ \ if\ \{\ \$LINEwidth\ >\ \$VARwidth\ \}\ \{\n\ \ \ \ \ \ \ \ \ set\ VARwidth\ \$LINEwidth\ \n\ \ \ \ \ \ \}\n\n\ \ \ \}\n\ \ \ ##\ END\ OF\ foreach\ line\ \$VARlist\n\n\ \ \ ##\ For\ testing:\n\ \ \ #\ \ \ puts\ \"VARwidth:\ \$VARwidth\"\n\n\n\ \ \ ###############################################################\n\ \ \ ##\ NOTE:\ VARwidth\ works\ for\ a\ fixed-width\ font\ used\ for\ the\n\ \ \ ##\ \ \ \ \ \ \ text\ widget\ ...\ BUT\ the\ programmer\ may\ need\ to\ be\n\ \ \ ##\ \ \ \ \ \ \ careful\ that\ the\ contents\ of\ VARtext\ are\ all\n\ \ \ ##\ \ \ \ \ \ \ countable\ characters\ by\ the\ 'string\ length'\ command.\n\ \ \ ###############################################################\n\n\n\ \ \ #####################################\n\ \ \ ##\ SETUP\ 'TOP\ LEVEL'\ HELP\ WINDOW.\n\ \ \ #####################################\n\n\ \ \ catch\ \{destroy\ \$toplevName\}\n\ \ \ toplevel\ \ \$toplevName\n\n\ \ \ #\ wm\ geometry\ \$toplevName\ 600x400+100+50\n\n\ \ \ wm\ geometry\ \$toplevName\ +100+50\n\n\ \ \ wm\ title\ \ \ \ \ \$toplevName\ \"Note\"\n\ \ \ #\ wm\ title\ \ \ \$toplevName\ \"Note\ to\ \$env(USER)\"\n\n\ \ \ wm\ iconname\ \ \$toplevName\ \"Note\"\n\n\n\ \ \ #####################################\n\ \ \ ##\ In\ the\ frame\ '\$toplevName'\ -\n\ \ \ ##\ DEFINE\ THE\ TEXT\ WIDGET\ and\n\ \ \ ##\ its\ two\ scrollbars\ ---\ and\n\ \ \ ##\ DEFINE\ an\ OK\ BUTTON\ widget.\n\ \ \ #####################################\n\n\ \ \ if\ \{\$VARheight\ >\ 10\}\ \{\n\ \ \ \ \ \ text\ \$toplevName.text\ \\\n\ \ \ \ \ \ \ \ \ -wrap\ none\ \\\n\ \ \ \ \ \ \ \ \ -font\ fontTEMP_varwidth\ \\\n\ \ \ \ \ \ \ \ \ -width\ \ \$VARwidth\ \\\n\ \ \ \ \ \ \ \ \ -height\ \$VARheight\ \\\n\ \ \ \ \ \ \ \ \ -bg\ \"#f0f0f0\"\ \\\n\ \ \ \ \ \ \ \ \ -relief\ raised\ \\\n\ \ \ \ \ \ \ \ \ -bd\ 2\ \\\n\ \ \ \ \ \ \ \ \ -yscrollcommand\ \"\$toplevName.scrolly\ set\"\ \\\n\ \ \ \ \ \ \ \ \ -xscrollcommand\ \"\$toplevName.scrollx\ set\"\n\n\ \ \ \ \ \ scrollbar\ \$toplevName.scrolly\ \\\n\ \ \ \ \ \ \ \ \ -orient\ vertical\ \\\n\ \ \ \ \ \ \ \ \ -command\ \"\$toplevName.text\ yview\"\n\n\ \ \ \ \ \ scrollbar\ \$toplevName.scrollx\ \\\n\ \ \ \ \ \ \ \ \ -orient\ horizontal\ \\\n\ \ \ \ \ \ \ \ \ -command\ \"\$toplevName.text\ xview\"\n\ \ \ \}\ else\ \{\n\ \ \ \ \ \ text\ \$toplevName.text\ \\\n\ \ \ \ \ \ \ \ \ -wrap\ none\ \\\n\ \ \ \ \ \ \ \ \ -font\ fontTEMP_varwidth\ \\\n\ \ \ \ \ \ \ \ \ -width\ \ \$VARwidth\ \\\n\ \ \ \ \ \ \ \ \ -height\ \$VARheight\ \\\n\ \ \ \ \ \ \ \ \ -bg\ \"#f0f0f0\"\ \\\n\ \ \ \ \ \ \ \ \ -relief\ raised\ \\\n\ \ \ \ \ \ \ \ \ -bd\ 2\ \n\ \ \ \}\n\n\ \ \ button\ \$toplevName.butt\ \\\n\ \ \ \ \ \ -text\ \"OK\"\ \\\n\ \ \ \ \ \ -font\ fontTEMP_varwidth\ \\\n\ \ \ \ \ \ -command\ \ \"destroy\ \$toplevName\"\n\n\ \ \ ###############################################\n\ \ \ ##\ PACK\ *ALL*\ the\ widgets\ in\ frame\ '\$toplevName'.\n\ \ \ ###############################################\n\n\ \ \ ##\ Pack\ the\ bottom\ button\ BEFORE\ the\n\ \ \ ##\ bottom\ x-scrollbar\ widget,\n\n\ \ \ pack\ \ \$toplevName.butt\ \\\n\ \ \ \ \ \ -side\ bottom\ \\\n\ \ \ \ \ \ -anchor\ center\ \\\n\ \ \ \ \ \ -fill\ none\ \\\n\ \ \ \ \ \ -expand\ 0\n\n\n\ \ \ if\ \{\$VARheight\ >\ 10\}\ \{\n\ \ \ \ \ \ ##\ Pack\ the\ scrollbars\ BEFORE\ the\ text\ widget,\n\ \ \ \ \ \ ##\ so\ that\ the\ text\ does\ not\ monopolize\ the\ space.\n\n\ \ \ \ \ \ pack\ \$toplevName.scrolly\ \\\n\ \ \ \ \ \ \ \ \ -side\ right\ \\\n\ \ \ \ \ \ \ \ \ -anchor\ center\ \\\n\ \ \ \ \ \ \ \ \ -fill\ y\ \\\n\ \ \ \ \ \ \ \ \ -expand\ 0\n\n\ \ \ \ \ \ ##\ DO\ NOT\ USE\ '-expand\ 1'\ HERE\ on\ the\ Y-scrollbar.\n\ \ \ \ \ \ ##\ THAT\ ALLOWS\ Y-SCROLLBAR\ TO\ EXPAND\ AND\ PUTS\n\ \ \ \ \ \ ##\ BLANK\ SPACE\ BETWEEN\ Y-SCROLLBAR\ &\ THE\ TEXT\ AREA.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ pack\ \$toplevName.scrollx\ \\\n\ \ \ \ \ \ \ \ \ -side\ bottom\ \\\n\ \ \ \ \ \ \ \ \ -anchor\ center\ \\\n\ \ \ \ \ \ \ \ \ -fill\ x\ \ \\\n\ \ \ \ \ \ \ \ \ -expand\ 0\n\n\ \ \ \ \ \ ##\ DO\ NOT\ USE\ '-expand\ 1'\ HERE\ on\ the\ X-scrollbar.\n\ \ \ \ \ \ ##\ THAT\ KEEPS\ THE\ TEXT\ AREA\ FROM\ EXPANDING.\n\n\ \ \ \ \ \ pack\ \$toplevName.text\ \\\n\ \ \ \ \ \ \ \ \ -side\ top\ \\\n\ \ \ \ \ \ \ \ \ -anchor\ center\ \\\n\ \ \ \ \ \ \ \ \ -fill\ both\ \\\n\ \ \ \ \ \ \ \ \ -expand\ 1\n\ \ \ \}\ else\ \{\n\ \ \ \ \ \ pack\ \$toplevName.text\ \\\n\ \ \ \ \ \ \ \ \ -side\ top\ \\\n\ \ \ \ \ \ \ \ \ -anchor\ center\ \\\n\ \ \ \ \ \ \ \ \ -fill\ both\ \\\n\ \ \ \ \ \ \ \ \ -expand\ 1\n\ \ \ \}\n\n\n\ \ \ #####################################\n\ \ \ ##\ LOAD\ MSG\ INTO\ TEXT\ WIDGET.\n\ \ \ #####################################\n\n\ \ \ ##\ \ \$toplevName.text\ delete\ 1.0\ end\n\ \n\ \ \ \$toplevName.text\ insert\ end\ \$VARtext\n\ \ \ \n\ \ \ \$toplevName.text\ configure\ -state\ disabled\n\ \ \n\}\n##\ END\ OF\ PROC\ 'popup_msgVarWithScroll'\n\n\n##+########################\n##\ END\ of\ PROC\ definitions.\n##+########################\n##\ Set\ HELPtext\ var.\n##+########################\n\n\nset\ HELPtext\ \"\\\n\\\ \\\ **\ HELP\ for\ this\ 'Memory\ and\ Swap\ Usage'\ Monitoring\ Utility\ **\n\nThis\ utility\ is\ meant\ to\ show\ a\ GUI\ that\ holds\ a\ pair\ of\ntachometer-style\ meters.\ The\ needles\ on\ the\ meters\ are\ updated\nperiodically\ ---\ whenever\ the\ user\ chooses\ to\ click\ on\ the\n'Refresh'\ button\ ---\ to\ show\ the\ PERCENT\ of\ available\nMEMORY\ and\ SWAP\ resources\ in\ use,\ on\ this\ computer\ ---\nas\ well\ as\ the\ actual\ TOTAL\ and\ USED\ values\ of\ the\ those\ntwo\ resources.\n\nThis\ Tcl-Tk\ script\ was\ developed\ on\ Linux\ and\ uses\ the\ 'free'\ncommand\ to\ get\ the\ memory\ and\ swap\ data\ to\ determine\ where\ to\nrelocate\ the\ position\ of\ the\ needles\ on\ the\ meters.\n\nThere\ are\ a\ couple\ of\ Tk\ 'canvas'\ widgets\ that\ contain\ two\ meter\ images\n---\ one\ for\ percent-memory-in-use\ and\ one\ for\ percent-swap-in-use.\n\n\n***************************************\nWINDOW\ RESIZE\ (an\ experimental\ feature):\n\nWe\ can\ allow\ the\ user\ to\ resize\ the\ window\ rather\ than\ using\ a\ fixed\nwindow\ (and\ fixed\ meters)\ size.\ If\ the\ user\ resizes\ the\ window,\ the\n'Refresh'\ button\ can\ be\ used\ to\ force\ the\ meters\ to\ be\ resized\naccording\ to\ the\ new\ window\ size.\ (The\ meters\ may\ be\ resized\ such\ that\nthey\ are\ 'too\ tall'\ for\ the\ new\ window\ size.\ Just\ pull\ the\ window\ down,\nto\ see\ the\ entire\ meters.)\n\n************************************\nTHE\ SCRIPT\ USED\ to\ update\ the\ meters:\n\nA\ Tcl\ 'exec'\ command\ calls\ on\ a\ separate\ shell\ script\ ---\n'get_memory_and_swap.sh'\ ---\ that\ uses\ the\ 'free'\ command\nto\ get\ the\ memory\ and\ swap\ data\ (total\ and\ used)\ and\nextract-and-format\ the\ data\ for\ return\ to\ this\ Tk\ script.\n\nIf\ the\ 'free'\ command\ is\ not\ available\ on\ your\ computer,\nyou\ may\ have\ to\ install\ it\ ---\ or\ edit\ the\ shell\ script\ to\ use\na\ different\ command\ to\ get\ the\ memory\ and\ swap\ data.\n\n***********************\nCAPTURING\ THE\ GUI\ IMAGE:\n\nA\ screen/window\ capture\ utility\ (like\ 'gnome-screenshot'\non\ Linux)\ can\ be\ used\ to\ capture\ the\ GUI\ image\ in\ a\ PNG\nor\ GIF\ file,\ say.\n\nIf\ necessary,\ an\ image\ editor\ (like\ 'mtpaint'\ on\ Linux)\ncan\ be\ used\ to\ crop\ the\ window\ capture\ image.\ \ The\ image\ncould\ also\ be\ down-sized\ ---\ say\ to\ make\ a\ smaller\ image\nsuitable\ for\ use\ in\ a\ web\ page\ or\ an\ email.\n\"\n\n\n##+################################################################\n##+################################################################\n##\ Additional\ GUI\ INITIALIZATION:\ \ Mainly\ to\n##\ \ -\ Put\ the\ 2\ meters\ on\ their\ 2\ canvases,\ with\ 'make_tachometers'.\n##\ \ -\ Start\ an\ execution\ loop\ for\ the\ 'update_needles'\ proc.\n##+################################################################\n\n##+###################################################\n##\ Set\ the\ scale\ widget\ var\ for\ initial\ 'refresh\ rate'\n##\ (actually\ wait-time\ =\ 'wave-length',\ not\ 'frequency')\n##\ ---\ in\ seconds.\n##\ COMMENTED.\ There\ were\ technical\ problems\ with\n##\ using\ a\ wait-time.\ The\ GUI\ became\ unusable\ during\n##\ the\ wait.\ A\ different\ technique\ is\ needed.\n##+###################################################\n\n#\ set\ WAITseconds\ 60.0\n\n##\ FOR\ TESTING:\n#\ \ set\ WAITseconds\ 1.0\n\n\n##+#################################################\n##\ Draw\ the\ 2\ tachometers\ (without\ needles).\n##+#################################################\n##\ Need\ 'update'\ here\ to\ set\ the\ size\ of\ the\ canvases,\n##\ because\ 'make_tachometers'\ uses\ 'winfo'\ to\ get\n##\ the\ width\ and\ height\ of\ some\ frames\ and\ canvases.\n##+#################################################\n\nupdate\nmake_tachometers\n\n\n##+#################################################\n##\ Set\ a\ resize\ binding\ on\ the\ canvas\ ---\n##\ to\ redraw\ the\ tachometers\ and\ needles\n##\ if\ the\ window\ is\ resized.\n##\n##\ DE-ACTIVATED,\ for\ now.\n##\ (Code\ is\ here\ for\ future\ experimentation.\n##\ \ It\ is\ not\ easy\ to\ avoid\ extraneous\ redraws\ of\n##\ \ the\ GUI\ as\ the\ window\ is\ being\ dragged/resized.)\n##+#################################################\n\nif\ \{0\}\ \{\nset\ draw_wait0or1\ 0\nset\ PREVcanvasesWidthPx\ \ \[winfo\ width\ \ .fRcanvases\]\nset\ PREVcanvasesHeightPx\ \[winfo\ height\ .fRcanvases\]\nbind\ .fRcanvases\ <Configure>\ \"ReDraw_if_canvases_resized\"\n\}\n\n\n##+############################################\n##\ Do\ an\ initial\ draw\ of\ the\ needles.\n##\n##\ In\ an\ attempt\ to\ use\ the\ \$WAITseconds\ var\ above,\n##\ this\ 'update_needles'\ call\ started\ a\ recursive-loop\n##\ to\ keep\ updating\ the\ needles.\n##\n##\ The\ proc\ 'update_needles'\ called\ itself,\ recursively,\n##\ after\ waiting\ \$WAITseconds.\ NOTE:\n##\n##\ I\ am\ leery\ of\ that\ kind\ of\ recursion\ leading\n##\ to\ ever-increasing\ memory\ consumption\ or\ the\n##\ generation\ of\ an\ ever-increasing\ 'stack'\ of\n##\ processes\ ---\ or\ 'stack'\ of\ 'whatever'.\n##\n##\ Before\ trying\ recursion,\ I\ tried\ a\ 'while'\ loop\n##\ here.\ \ But\ I\ needed\ to\ 'drop\ into'\ the\ Tk\ event\n##\ handling\ loop\ here,\ and\ I\ could\ not\ do\ that\n##\ if\ I\ put\ a\ 'while'\ loop\ here\ that\ keeps\n##\ calling\ 'update_needles'\ after\ a\ wait\ of\n##\ \$WAITseconds.\n##\n##\ In\ any\ case,\ even\ the\ 'recursive'\ 'update_needles'\n##\ proc\ technique\ led\ to\ GUI\ unresponsiveness\ problems,\n##\ so\ I\ went\ to\ requiring\ the\ user\ to\ use\ the\ 'Refresh'\n##\ button\ to\ do\ the\ needle\ updates.\n##+############################################\n\nupdate_needles\n\n======\n\n<<discussion>>\n\nAnd\ here\ is\ the\ code\ for\ the\ shell\ script\ called\ by\ this\ Tk\ script.\n\nYou\ can\ put\ this\ script\ in\ the\ same\ directory\ with\ the\ Tk\ script.\nThe\ Tk\ script\ includes\ some\ code\ (involving\ the\ 'argv0'\ variable)\nto\ determine\ the\ location\ of\ the\ shell\ script\ by\ extracting\ the\ name\nof\ the\ directory\ in\ which\ the\ Tk\ script\ lies.\n\n<<discussion>>Code\ for\ the\ shell\ script\ 'get_memory_and_swap.sh'\ :\n\n======\n\n#!/bin/sh\n##\n##\ SCRIPT\ NAME:\ get_memory_and_swap.sh\n##\n#############################################################################\n##\ PURPOSE:\n##\ \ \ \ Gets\ 'memory'\ and\ 'swap'\ data\ from\ output\ of\ the\ 'free'\ command.\n##\n##\ Example\ output\ from\ the\ 'free\ -m\ -o'\ command:\n##\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ total\ \ \ \ \ \ \ used\ \ \ \ \ \ \ free\ \ \ \ \ shared\ \ \ \ buffers\ \ \ \ \ cached\n##\ Mem:\ \ \ \ \ \ \ \ \ \ 3275\ \ \ \ \ \ \ \ 595\ \ \ \ \ \ \ 2679\ \ \ \ \ \ \ \ \ \ 0\ \ \ \ \ \ \ \ 114\ \ \ \ \ \ \ \ 243\n##\ Swap:\ \ \ \ \ \ \ \ \ 2290\ \ \ \ \ \ \ \ \ \ 0\ \ \ \ \ \ \ 2290\n##\n##\ where\ '-m'\ means\ the\ data\ is\ shown\ in\ megabytes\ instead\ of\ the\ default\ of\n##\ kilobytes\ ---\ and\ '-o'\ means\ that\ a\ line\ of\ buffer/cache\ data\ is\ not\ shown.\n##\n##\ This\ script\ gets\ the\ data\ from\ the\ 'total'\ and\ 'used'\ columns.\n##\n#############################################################################\n##\ CALLED\ BY:\ a\ Tk\ GUI\ script\ that\ shows\ 'memory'\ and\ 'swap'\ data\n##\ \ \ \ \ \ \ \ \ \ \ \ as\ needle\ readings\ on\ a\ couple\ of\ meters\ (dials)\ drawn\n##\ \ \ \ \ \ \ \ \ \ \ \ on\ a\ Tk\ canvas\ ---\ Tk\ script\ name:\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ meters_memory_swap.tk\n##\n#############################################################################\n##\ MAINTENANCE\ HISTORY:\n##\ Updated\ by:\ Blaise\ Montandon\ 2013aug08\ Started\ this\ script\ on\ Linux,\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ using\ Ubuntu\ 9.10\ (2009\ October,\n##\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'Karmic\ Koala').\n##\ Updated\ by:\ Blaise\ Montandon\ 20.......\n#############################################################################\n\n##\ FOR\ TESTING:\n#\ \ set\ -x\n\n#\ FREEOUT=`free\ -m\ -o\ |\ tail\ -2\ |\ cut\ -c6-30\ |\ tr\ '\\n'\ '\ '\ |\ sed\ 's/\ \ */\ /g'`\n\nfree\ -m\ -o\ |\ tail\ -2\ |\ cut\ -c6-30\ |\ tr\ '\\n'\ '\ '\ |\ sed\ 's/\ \ */\ /g'\n\n======\n\n<<discussion>>\n\n------\n\n'''SIMILAR\ UTILITIES:'''\n\nThere\ are\ several\ more\ 'meter\ utilities'\ on\ my\ 'to-do'\ list\nat\ the\ bottom\ of\ my\ 'bio'\ page\ at\ \[uniquename\]\ ---\ in\ the\ 'CME'\ (Code\ for\nMEters)\ group.\n\nIn\ particular,\ I\ may\ make\ a\ meter\ utility\ that\ shows\ network\ activity\n---\ and\ a\ meter\ utility\ that\ shows\ CPU\ activity\ (preferably\ for\ all\ the\ CPU's\non\ multiple\ CPU\ computers,\ which\ are\ everywhere\ nowadays).\n\n------\n\n'''IN\ CONCLUSION'''\n\nAs\ I\ have\ said\ on\ several\ other\ code-donation\ pages\ on\ this\ wiki\ ...\n\nThere's\ a\ lot\ to\ like\ about\ a\ utility\ that\ is\ 'free\ freedom'\ ---\nthat\ is,\ no-cost\ and\ open-source\ so\ that\ you\ can\ modify/enhance/fix\nit\ without\ having\ to\ wait\ for\ someone\ else\ to\ do\ it\ for\ you\n(which\ may\ be\ never).\n\nA\ BIG\ THANK\ YOU\ to\ Ousterhout\ for\ starting\ Tcl-Tk,\ and\ a\ BIG\ THANK\ YOU\nto\ the\ Tcl-Tk\ developers\ and\ maintainers\ who\ have\ kept\ the\ simply\ MAH-velous\n'wish'\ interpreter\ going.\n\n----\n\n<<discussion>>\n\n\ \ \ *\ But\ I\ found\ that\ there\ were\ technical\ problems\ with\ using\ the\ wait-time.\ Namely,\ in\ my\ attempt\ at\ implementation,\ the\ GUI\ became\ essentially\ non-interactive\ during\ the\ wait\ time.\n\n\[RLE\]\ (2013-09-01):\ Your\ comment\ at\ the\ end\ of\ the\ script\ explains\ what\ was\ wrong.\ \ You\ were\ never\ actually\ dropping\ into\ the\ Tk\ event\ loop,\ which\ is\ why\ your\ GUI\ got\ \"stuck\"\ with\ automatic\ updates.\ \ What\ you\ need\ to\ do\ is:\n\n\ \ \ 1.\ reinstate\ the\ wait\ time\ variable\ as\ an\ integer\ value\ in\ milli-seconds\ of\ wait\ time\;\n\ \ \ 2.\ modify\ your\ \"update_needles\"\ proc\ to\ do,\ as\ the\ very\ last\ command\ after\ the\ proc\ finishes\ the\ rest\ of\ its\ work\ the\ following:\n\n\ \ after\ \$::WAITmilliseconds\ update_needles\n\nAnd,\ change\ the\ last\ command\ in\ your\ script\ from\ \"update_needles\"\ to\ the\ following:\n\n\ \ after\ idle\ update_needles\n\nAt\ which\ point\ you\ will\ have\ the\ auto-update\ you\ wanted,\ the\ responsive\ GUI\ you\ wanted,\ and\ not\ have\ the\ recursive\ stack\ consumption\ you\ feared\ from\ update_needles\ calling\ itself.\ \ After\ you\ make\ this\ change,\ you\ can\ reinstate\ your\ slider\ idea\ to\ modify\ the\ WAITmilliseconds\ variable\ (likely\ adjusting\ so\ that\ a\ user\ see's\ seconds\ instead\ of\ milliseconds).\n\nYou\ can\ also\ replace\ your\ existing\ \[foreach\]\ loop\ over\ the\ output\ of\ get_memory_and_swap.sh\ and\ the\ entire\ shell\ script\ itself\ with\ this\ one\ line\ of\ Tcl:\n\n======\n\ \ regexp\ \{Mem:\ +(\[0-9\]+)\ +(\[0-9\]+).*Swap:\ +(\[0-9\]+)\ +(\[0-9\]+)\}\ \[\ exec\ free\ -m\ -o\ \]\ ->\ MEMtot\ MEMused\ SWAPtot\ SWAPused\n======\n\nor\ if\ you\ prefer\ two\ lines:\n\n======\n\ \ set\ freeinfo\ \[\ exec\ free\ -m\ -o\ \]\n\ \ regexp\ \{Mem:\ +(\[0-9\]+)\ +(\[0-9\]+).*Swap:\ +(\[0-9\]+)\ +(\[0-9\]+)\}\ \$freeinfo\ ->\ MEMtot\ MEMused\ SWAPtot\ SWAPused\n======\n\n----\n\n\[uniquename\]\ 2013sep02\ -\ Thanks\ for\ the\ feedback,\ RLE.\ Finally,\nafter\ 15+\ years\ of\ Tcl-Tk\ programming,\ I\ am\ introduced\ to\ a\ use\ for\nthe\ 'after\ idle'\ command.\ (There\ is\ always\ more\ to\ be\ learned\ about\ Tcl-Tk\n---\ or\ about\ any\ programming\ language\ ---\ or\ about\ life.\ Whenever\ I\ hear/read\ of\nsomeone\ saying\ they\ are\ bored,\ I\ have\ to\ think\ they\ are\ really\ unimaginative\nat\ that\ point\ in\ their\ life\ ---\ and\ need\ to\ be\ introduced\ to\ Tcl-Tk.)\n\nI\ am\ still\ a\ little\ concerned\ about\ having\ 'update_needles'\ recursively\ncalling\ itself.\ (I\ would\ be\ 'mightily'\ concerned\ if\ the\ wait-time\ were\na\ fraction\ of\ a\ second\ ---\ but,\ in\ this\ particular\ application,\ I\ would\nprobably\ have\ the\ wait\ time\ set\ at\ about\ 2\ minutes,\ in\ most\ use\ cases.)\n\nFunny\ thing,\ though.\ This\ utility\ is\ just\ the\ thing\ to\ use\ to\ check\nif\ the\ recursive\ calls\ are\ using\ more\ and\ more\ memory.\ Just\ use\ a\ wait\ time\nof\ about\ 0.1\ second\ and\ let\ it\ run\ for\ an\ hour\ or\ two.\ Check\ the\ GUI\noccasionally\ to\ see\ if\ the\ needle(s)\ is(are)\ moving.\n\n\[RLE\]\ (2013-09-02):\ The\ \[after\]\ method\ is\ not\ recursive.\ \ \[After\]\ is\ a\ general\ delay\ and\ scheduler\ command.\ \ The\ last\ command\ of\ update_needles\"\ being\ \"after\ \$waittime\ update_needles\"\ means\ \"schedule\ a\ task\ to\ execute\ \"update_needles\"\ in\ \$waittime\ milli-seconds.\ \ No\ recursive\ calls.\ \ Once\ the\ future\ task\ is\ scheduled,\ the\ current\ update_needles\ call\ exists.\ \ At\ a\ later\ time,\ a\ new\ call\ to\ update_needles\ will\ occur\ from\ the\ Tk\ event\ loop\ machinery.\n\nEven\ if\ the\ wait\ time\ were\ 1\ milli-second,\ there\ would\ still\ be\ no\ recursive\ calling.\ The\ effect\ is\ that\ \"update_needles\"\ would\ be\ executed\ every:\ (time\ to\ perform\ update_needles)\ +\ (wait\ time\ for\ after\ command)\ seconds.\ \ So\ you\ would\ likely\ not\ get\ 1ms\ execution,\ instead\ if\ update\ needles\ takes\ 250ms,\ you'd\ get\ a\ call\ every\ 251ms.\ \ But\ no\ recursion.\n\n\[uniquename\]\ 2013sep02\ It\ still\ looks\ recursive\ to\ me\ ---\ 'update_needles'\ is\ calling\ itself.\nThe\ only\ way\ that\ it\ would\ NOT\ be\ recursive\ is\ if\ the\ 'after'\ command\ somehow\ 'killed'\nthe\ proc\ that\ is\ calling\ the\ 'after'\ command\ and,\ essentially,\ 'forks\ off'\ a\ new\n'update_needles'\ proc\ while\ 'recovering'\ any\ resources\ used\ by\ the\ previous\ call\ to\n'update_needles'.\n\nPerhaps\ I\ did\ not\ explain\ well\ what\ I\ tried,\ in\ the\ comments\ at\ the\ bottom\ of\ the\ script.\nI\ tried\ TWO\ techniques:\n\ \ \ *\ a\ 'while'\ loop\n\ \ \ *\ the\ recursive\ proc-calling-itself\ technique.\nNeither\ one\ worked\ out\ well.\ The\ GUI\ became\ unresponsive.Hence\ I\ went\ to\ the\ 'Refresh'\nbutton\ technique.\ I\ will\ try\ to\ improve\ the\ comments\ at\ the\ bottom\ of\ the\ code\ above.\n\nIn\ any\ case,\ most\ concerns\ that\ I\ have\ about\ using\ that\ proc-calling-itself\ technique\nwould\ be\ addressed\ by\ trying\ the\ experiment\ that\ I\ pointed\ out\ above.\n\nBy\ the\ say,\ in\ thinking\ about\ the\ 'after\ idle'\ usage\ that\ you\ suggested,\ I\ realized\nthat\ I\ do\ not\ need\ that.\ The\ last\ call\ in\ the\ code\ was\ to\ 'update_needles',\ and\ then\nthe\ script\ 'drops\ into'\ the\ Tk\ event\ handling\ loop\ ---\ with\ no\ need\ for\ 'after\ idle'.\n\n\[RLE\]\ (2013-09-02):\ Except\ that\ based\ upon\ your\ comments\ above,\ you\ did\ not\ actually\ try\ the\ \[after\]\ command\ method.\ \ Neither\ a\ while\ loop\ nor\ a\ recursive\ call-itself\ is\ the\ \[after\]\ command\ method.\n\nChange\ your\ script\ in\ this\ way:\n\n===none\n---\ tach.orig\ \ \ 2013-09-02\ 18:35:07.805534592\ -0400\n+++\ tach.fixed\ \ 2013-09-02\ 18:35:45.717534262\ -0400\n@@\ -1149,7\ +1149,7\ @@\n\ \ \ \ ##\ \ do\ not\ 'fall\ into'\ the\ normal\ Tk\ event\ handling\ loop.)\n\ \ \ \ ############################################################\n\ \n-\ \ \ update\n+\ \ \ after\ 5000\ update_needles\n\ \n\ \}\n\ ##\ END\ OF\ proc\ 'update_needles'\n@@\ -1674,4\ +1674,4\ @@\n\ ##\ button\ to\ do\ the\ needle\ updates.\n\ ##+############################################\n\ \n-update_needles\n+after\ idle\ update_needles\n==\n\nAnd\ you\ will\ get\ updates\ every\ 5\ seconds.\n\nThe\ key\ is\ that\ \"update_needles\"\ must\ use\ \[after\]\ to\ reschedule\ itself,\ it\ can\ not\ recursively\ call\ itself.\n\n<<categories>>\ GUI\ |\ Widget} CALL {my revision {A Pair of Tachometer-style Meters --- for Memory and Swap}} CALL {::oo::Obj1069461 process revision/A+Pair+of+Tachometer-style+Meters+---+for+Memory+and+Swap} CALL {::oo::Obj1069459 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