#!/usr/bin/wish ## ##+######################################################################## ## NOTE: ## If the 'wish' interpreter is in a different directory, such as ## /usr/local/bin, you can make a soft-link from 'wish' there to ## /usr/bin/wish, as root, with a command like ## ln -s /usr/local/bin/wish /usr/bin/wish ##+######################################################################## ## Tk SCRIPT NAME: plotquik_PointsLines_XYdataEntry.tk ## ## --- adapted from the script 'plot_quik_xy_points-lines.tk' ## in the old 'feHandyTools' subsystem of the 'Freedom Environment' ## subsystems at www.freedomenv.com --- adapted for putting a ## 'standalone' utility (with no 'source' statements) in the ## FE 'tkGooies' system. ##+####################################################################### ## PURPOSE: An intuitive, easy-to-use X-Y-AXIS POINT/LINE PLOT UTILITY ## that can be used to make 'presentation quality' plots ## QUICKLY. ## _____________________________________________________________ ## ## This Tk script presents a GUI with a canvas widget showing ## a 2-D point or line plot --- with titles and labels that ## can be dragged with the mouse. ## ## This script presents entry fields in the GUI to prompt for ## x,y data and plot-title and axis titles and limits. ## _____________________________________________________________ ## ## This is a plotting-utility implementation using BASIC ## Tcl-Tk commands, i.e. not requiring an 'extension' of Tcl or Tk. ## ## Unfortunately, there do not seem to be any FAIRLY GENERAL, yet ## RELATIVELY SIMPLE, xy-point plotting scripts at Tcl-Tk archive ## sites --- even in 2013, more than 20 years after the development ## of the necessary Tk canvas facilities to support plotting. ## ## Nor are such general, easy-to-use xy point/line plotting Tk scripts ## available via web searches on keyword strings such as ## 'bin wish canvas' or 'bin wish oval' or 'bin wish line'. ## ## Even searches on 'canvas' and 'oval' on the wiki.tcl.tk site, ## in early 2013, yield only simplistic line plot 'demos' that are ## not suited to general and FAST point/line plots --- with entry ## fields for quick entry of user data. ## ## This script is meant to fill that long-time void. ## _____________________________________________________________ ## ## SOURCES and CREDITS: ## ## The technique of dragging canvas items came from the Tcl-Tk demo in ## /usr/local/lib/tk4.0/demos/plot.tcl (on SGI-IRIX Unix, 1995 May 26). ## However, that script allowed the user to drag the data points. ## This script allows the user to drag titles and labels. ## ## On Linux (for example, Ubuntu 9.10, circa 2009), see ## /usr/share/doc/tk8.4/examples/plot.tcl ## or /usr/share/doc/tk8.5/examples/plot.tcl ## There are 60-plus other Tcl-Tk code examples in the ## 'examples' directory. ## ## See also 'create oval' plot scripts like ## 'items.tcl' and 'twind.tcl' in /usr/share/doc/tk8.x/examples/. ## These scripts provide examples of procs to move 'items' around ## on the canvas with a mouse. ## ##+##################################################################### ## ## INPUTS (via entry fields on the GUI): ## plot title, x-y data, xy-axis titles, xy-axis min-max ## ## OUTPUT: Intended for screen/window capture to an image file with a ## screen-capture tool (such as 'gnome-screenshot' on Linux). ## ## The image could be cropped with an image editor (such as ## 'mtpaint' on Linux) and the cropped image could be printed ## using an image view-print utility (such as 'eog' = Eye of ## Gnome, on Linux) --- or a web browser. ## ## If you are going to print the image, you will probably ## want to change the background color to white, via the ## 'CanvasColor' button at the top of the GUI. ## ## (For another hard-copy option, a Postscript-Print button ## and proc could be implemented.) ## ##+################# ## THE GUI WIDGETS: ## ## The options available to the user are indicated by ## the following 'sketch' of the GUI. ## ## In the sketch of the GUI below: ## ## SQUARE BRACKETS indicate a comment (not to be placed on the GUI). ## BRACES indicate a Tk 'button' widget. ## A COLON indicates that the text before the colon is on a 'label' widget. ## UNDERSCORES indicate a Tk 'entry' widget. ## ## CAPITAL-X indicates a Tk 'checkbutton' widget. ## CAPITAL-O indicates a Tk 'radiobutton' widget (if any). ## <----O----> indicates a Tk 'scale' widget (if any). ## ## ------------------------------------------------------------------------------------------------------- ## ## FRAMEnames ## VVVVVVVVVV ## ----------------------------------------------------------------------------------- ## tkPlotQuik - Points and/or Lines Graph ## [window title] ## ----------------------------------------------------------------------------------- ## ## .fRbuttons {Exit}{Help} X Lines X Border {CanvasColor}{UpdatePlot}{GetImg}{DwnCan}{UpCan}{PrtPreview}{Print} [entry field here shows a print command] ## ## .fRtitle_main Plot title: ________________________________________________________________________________ ## ## .fRtitles_xy X-axis title: ________________________________ Y-axis title: _______________________________ ## ## .fRlims_xy X-axis min: __________ X-axis max: __________ Y-axis min: __________ Y-axis max: __________ ## ## .fRvals_x X data values: _____________________________________________________________________________ ## ## .fRvals_y Y data values: _____________________________________________________________________________ ## ## .fRlow .fRlow.fRmsg .fRlow.fRplot ## [ an area here contains a brief [ an area here ## guide in a text or label widget contains a canvas widget ## ... ... ## many to be populated with ## ... ... ## lines 'items' whenever the 'UpdatePlot' button ## ... ... ## deep. in frame 'fRbuttons' is poked. ## ] ] ## ## --------------------------------------------------------------------------------------------------------------- ## ##+############## ## GUI components: ## ## From the GUI 'sketch' above, it is seen that the GUI consists of about ## ## - 9 button widgets ## - 10 label widgets ## - 10 entry widgets ## - 1 text widget (with scroll bars someday?) (or one more label instead) ## - 1 canvas widget (with scroll bars someday?) ## - 2 checkbutton widgets ## - 0 radiobutton widgets ## - 0 listbox widgets ## - 0 scale widgets ## ##+##################################################################### ## STRUCTURE OF THIS CODE: ## ## 0) Set general window parms (win-name, win-position, win-color-scheme, ## fonts, widget-geom-parms, win-size-control, text-array-for-labels-etc). ## 1a) Define ALL frames (and sub-frames, if any). ## 1b) Pack ALL frames and sub-frames. ## 2) Define & pack ALL widgets within frames, frame by frame. ## ## 3) Define key and mouse/touchpad/touch-sensitive-screen action ## BINDINGS, if any. ## 4) Define PROCS, if any. ## 5) Additional GUI INITIALIZATION (typically with one or two ## of the procs), if needed. ## ## In more detail: ## ## 1a) Define ALL frames: ## From the top-down on the GUI are several horizontal frames, ## stretching across the GUI: ## ## - 'fRbuttons' and several entry-widget frames for ## plot title, axis titles, axis limits, and data values. ## ## - Below those frames, across the GUI, is a container frame: 'fRlow'. ## ## There are 2 sub-frames on the left and right of the 'fRlow' frame: ## 'fRlow.fRmsg' and 'fRlow.fRplot' ## ## Help text is in the 'fRmsg' frame. ## The plot is in the 'fRplot' frame. ## ## 1b) Pack frames with appropriate '-side' '-anchor' '-fill' '-expand' ## parameters to get proper behavior of widgets within the frames, ## during window expansion. (Window expansion is allowed). ## ## 2) Define & pack all widgets in the frames -- basically going through ## frames & their interiors in top-to-bottom, left-to-right order: ## ## - 'fRbuttons' contains buttons -- ## Exit & Help & UpdatePlot & other buttons. ## ## - 'fRtitle_main' contains 1 label & 1 entry widget. ## - 'fRtitles_xy' contains 2 pairs of label & entry widgets. ## - 'fRlims_xy' contains 4 pairs of label & entry widgets. ## - 'fRvals_x' contains 1 label & 1 entry widget. ## - 'fRvals_y' contains 1 label & 1 entry widget. ## ## - 'fRlow.fRmsg' contains a message in a label (or text) widget. ## ## - 'fRlow.fRplot' contains a canvas widget (to be populated with ## 'items' whenever the 'UpdatePlot' button in ## 'fRbuttons' is poked). ## ## 3) Define BINDINGS: (See the BINDINGS code section.) ## ## To Drag plot-title and axis-titles (and tic-mark labels). ## Basically: ## - .fRame.canvas bind TAGtitles "itemSelect .fRame.canvas %x %y" ## - bind .fRame.canvas "itemMove .fRame.canvas %x %y" ## - .fRame.canvas bind TAGtitles ".fRame.canvas dtag TAGselected" ## ## 4) Define PROCS: (See the PROCS code section.) ## - 'update_plot' - Called by 'UpdatePlot' button; ## (Re)Sets contents of the plot canvas!! ## ## - 'set_margins' - Called by proc 'update_plot'. ## Sets margins around the 'plot rectangle'. ## ## - 'itemSelect' - Called by a binding on the canvas. ## Selects a canvas item. ## - 'itemMove' - Called by a binding on the canvas. ## Moves a canvas item. ## ## - 'draw_lines' - Called by 'update_plot' proc --- ## if 'Lines' checkbutton is ON. ## - 'draw_border' - Called by 'update_plot' proc --- ## if 'Border' checkbutton is ON. ## ## - 'canvas_color' - Called by 'CanvasColor' button. ## ## - 'downsize_canvas' - Called by 'DwnCan' button. ## - 'upsize_canvas' - Called by 'UpCan' button. ## - 'resize_win' - Called by the 'downsize_canvas' and ## 'upsize_canvas' procs. ## ## - 'print_preview' - Called by 'PrtPreview' button. ## - 'print_plot' - Called by 'Print' button. ## ## - 'getPut_image' - Called by 'GetImg' button. (Implement later.) ## ## - 'popup_msgVarWithScroll' - Called by 'Help' button. ## ## 5) Additional GUI initialization: ## Set various directory and helper-app and plot parameter variables. ## Set some sample data for the entry fields. ## Issue 'update_plot' to present an intitial demo plot on the canvas. ## ##+####################################################################### ## DEVELOPED WITH: Tcl-Tk 8.5 on Ubuntu 9.10 (2009-october, 'Karmic Koala') ## ## $ wish ## % puts "$tcl_version $tk_version" ## ## showed ## 8.5 8.5 ## but this script should work in most previous 8.x versions, and probably ## even in some 7.x versions (if font handling is made 'old-style'). ##+######################################################################## ## MAINTENANCE HISTORY: ## Started by: Blaise Montandon 2013jul18 Started development, on Ubuntu 9.10, ## based on my code ## 'plot_quik_xy_points-lines.tk' ## in the 'feHandyTools' subsystem of ## the 'Freedom Environment' subsystems ## at www.freedomenv.com --- adapted for ## donation of this code to the Tcl-Tk ## wiki at wiki.tcl.tk. Suspended. ## Updated by: Blaise Montandon 2017sep20 Restarted development for the FE ## 'tkGooies' system. ## Updated by: Blaise Montandon 2017sep21 Released this script at freedomenv.com. ## Updated by: Blaise Montandon 2017sep25 Chgd the 'TogLines' & 'TogBorder' ## buttons to 'Lines' & 'Border' checkbuttons. ## Implemented the 'GetImg' button. ## Updated by: Blaise Montandon 2017sep27 Added procs 'get_deciPlaces' and ## 'format_deciPlaces'. ##+######################################################################## ##+####################################################################### ## Set general window parms (win-title, win-position). ##+####################################################################### wm title . "tkPlotQuik - Points and/or Lines Graph" wm iconname . "PlotPointsLines" # catch { wm title . "$env(FE_WIN_TITLE)" } # catch { wm iconname . "$env(FE_ICON_TITLE)" } ##+################################### ## SET THE TOP WINDOW POSITION. ##+################################### wm geometry . +15+30 # catch {eval wm geometry . "$env(FE_WIN_LOC_GEOM)" } ##+####################################################################### ## SET COLOR SCHEME (palette) for the window and its widgets. ##+####################################################################### if {1} { ## Grayish palette set Rpal255 210 set Gpal255 210 set Bpal255 210 } if {0} { ## Bluish palette set Rpal255 180 set Gpal255 180 set Bpal255 255 } if {0} { ## Greenish palette set Rpal255 180 set Gpal255 255 set Bpal255 180 } if {0} { ## Reddish palette set Rpal255 255 set Gpal255 180 set Bpal255 180 } ## If env vars R255,G255,B255 were set, then we could use the following ## format statement to get a hex value for specifying tkGUI colors, ## after 'catch'-ing the three values into Rpal255,Gpal255,Bpal255 Tcl vars. # catch { set Rpal255 "$env(R255)" } # catch { set Gpal255 "$env(G255)" } # catch { set Bpal255 "$env(B255)" } set hexCOLORpal [format "#%02X%02X%02X" $Rpal255 $Gpal255 $Bpal255] ## Or could set palette from a hex-valued env var. # catch { set hexCOLORpal "$env(FE_PLOT_WINCOLOR)" } tk_setPalette "$hexCOLORpal" ##+####################################################### ## Set background colors for GUI widgets. ##+####################################################### set msgBKGD "#ffcccc" set entryBKGD "#f0f0f0" # set textBKGD "#f0f0f0" set textBKGD $msgBKGD set chkbuttBKGD "#c0c0c0" ## Following widgets are not used, yet. # set listboxBKGD "#f0f0f0" # # set radbuttBKGD "#c0c0c0" # set radbuttBKGD $msgBKGD # set radbuttSELECTCOLOR "#cccccc" # set scaleBKGD "#f0f0f0" ##+####################################################################### ## SET FONT VARS to use in the 'font create' statements below. ## ## We use a VARIABLE-WIDTH FONT for label and button widgets. ## ## We use a FIXED-WIDTH FONT for entry fields and ## text widgets and listboxes, if any. ##+####################################################################### set FONTsize 14 set FONT_SMALLsize 12 set fontFamily "comic sans ms" set FONTparms_varwidth " -family {$fontFamily} \ -size -$FONTsize -weight bold -slant roman" set FONTparms_SMALL_varwidth " -family {$fontFamily} \ -size -$FONT_SMALLsize -weight normal -slant roman " ## Some other possible (similar) variable width fonts: ## Arial ## Bitstream Vera Sans ## DejaVu Sans ## Droid Sans ## FreeSans ## Liberation Sans ## Nimbus Sans L ## Trebuchet MS ## Verdana # set fontFamily "dejavu sans mono" # set fontFamily "freemono" set fontFamily "liberation mono" set FONTparms_fixedwidth " -family {$fontFamily} \ -size -$FONTsize -weight bold -slant roman " set FONTparms_SMALL_fixedwidth " -family {$fontFamily} \ -size -$FONT_SMALLsize -weight normal -slant roman " ## Some other possible fixed width fonts (esp. on Linux): ## Andale Mono ## Bitstream Vera Sans Mono ## Courier 10 Pitch ## Liberation Mono ## Droid Sans Mono ## FreeMono ## Nimbus Mono L ## TlwgMono ##+##################################################################### ## DEFINE (temporary) FONT VARS to be used in '-font' widget specs below ## --- and for some plot titles. ##+##################################################################### eval font create fontTEMP_varwidth $FONTparms_varwidth eval font create fontTEMP_fixedwidth $FONTparms_fixedwidth eval font create fontTEMP_button $FONTparms_varwidth eval font create fontTEMP_chkbutt $FONTparms_varwidth eval font create fontTEMP_label $FONTparms_varwidth eval font create fontTEMP_text $FONTparms_fixedwidth eval font create fontTEMP_msg $FONTparms_fixedwidth eval font create fontTEMP_entry $FONTparms_fixedwidth # eval font create fontTEMP_listbox $FONTparms_fixedwidth eval font create fontTEMP_SMALL_varwidth $FONTparms_SMALL_varwidth eval font create fontTEMP_SMALL_fixedwidth $FONTparms_SMALL_fixedwidth eval font create fontTEMP_SMALL_button $FONTparms_SMALL_varwidth eval font create fontTEMP_SMALL_chkbutt $FONTparms_SMALL_varwidth eval font create fontTEMP_SMALL_label $FONTparms_SMALL_varwidth eval font create fontTEMP_SMALL_text $FONTparms_SMALL_fixedwidth eval font create fontTEMP_SMALL_msg $FONTparms_SMALL_fixedwidth eval font create fontTEMP_SMALL_entry $FONTparms_SMALL_fixedwidth # eval font create fontTEMP_SMALL_listbox $FONTparms_SMALL_fixedwidth ## For the text in the plot: eval font create fontTEMP_plottitle $FONTparms_varwidth ##+####################################################################### ## SET GEOM VARS FOR THE VARIOUS WIDGET DEFINITIONS. ## (e.g. padx, pady for buttons) ## ## Possible values for '-relief' are: ## flat, groove, raised, ridge, solid, and sunken. ##+####################################################################### ## For BUTTON widgets: set PADYpx_button 0 set PADXpx_button 0 set BDwidthPx_button 2 set RELIEF_button raised ## For LABEL widgets: set PADXpx_label 0 set PADYpx_label 0 set BDwidthPx_label 2 set RELIEF_label flat ## For ENTRY widgets: set BDwidthPx_entry 2 set RELIEF_entry sunken ## CHECKBUTTON geom parameters: set PADXpx_chkbutt 0 set PADYpx_chkbutt 0 set BDwidthPx_chkbutt 2 # set RELIEF_chkbutt raised set RELIEF_chkbutt ridge ## For TEXT widgets: set BDwidthPx_text 2 # set RELIEF_text raised set RELIEF_text ridge ## For CANVAS widgets: # set BDwidthPx_canvas 2 # set RELIEF_canvas raised set BDwidthPx_canvas 0 set RELIEF_canvas flat set initCanWidthPx 200 set initCanHeightPx 200 set minCanHeightPx 24 ## For LISTBOX widgets: # set BDwidthPx_listbox 2 ##+############################################################## ## Set a TEXT-ARRAY to hold text for buttons, labels, and other ## widgets on the GUI. ## NOTE: This can aid INTERNATIONALIZATION. This array can ## be set according to a nation/region parameter. ##+############################################################## ## if { "$VARlocale" == "en"} ## For '.fRbuttons' frame: set aRtext(buttonEXIT) "Exit" set aRtext(buttonHELP) "Help" set aRtext(buttonUPDATE) "UpdatePlot" set aRtext(buttonCANCOLOR) "CanvasColor" set aRtext(chkbuttLINES) "Lines" set aRtext(chkbuttBORDER) "Border" set aRtext(buttonIMG) "GetImg" set aRtext(buttonDWNCAN) "DwnCan" set aRtext(buttonUPCAN) "UpCan" set aRtext(buttonPRTPREVIEW) "PrtPreview" set aRtext(buttonPRINT) "Print" set aRtext(labelPRINTCMD) "PrintCommand:" ## For '.fRtitle_main' frame: set aRtext(labelPLOTTITLE) "PlotTitle:" ## For '.fRtitles_xy' frame: set aRtext(labelXAXISTITLE) "XaxisTitle:" set aRtext(labelYAXISTITLE) "YaxisTitle:" ## For '.fRlims_xy' frame: set aRtext(labelXAXISMIN) "XaxisMin:" set aRtext(labelXAXISMAX) "XaxisMax:" set aRtext(labelXTICDIST) "XticDist:" set aRtext(labelYAXISMIN) "YaxisMin:" set aRtext(labelYAXISMAX) "YaxisMax:" set aRtext(labelYTICDIST) "YticDist:" ## For '.fRvals_x' frame: set aRtext(labelXDATA) "XdataVals:" ## For '.fRvals_y' frame: set aRtext(labelYDATA) "YdataVals:" ## For '.fRlow.fRmsg' frame: set aRtext(labelHELPMSG) \ "To the right is a 'canvas' to contain a 2-dimensional data-points plot --- with or without lines. Recommended order of actions: 1. Increase the canvas AND plot size with the 'UpCan' button. Downsize with 'DwnCan'. Use the 'CanvasColor' button to change background color. 2. After making changes in any of the several entry fields, use the 'UpdatePlot' button. 3. You can drag any of the titles or tic-mark labels with mouse-button-1. When you use the 'UpdatePlot' button, titles and labels are returned to their initial locations (handy to restore labels if pulled off-canvas). You can drag labels back where wanted. 4.You can use a screen-grab, image- editor, and image-view-print utilities to make an image file or to print the plot." ## END OF if { "$VARlocale" == "en"} ##+################################################################### ## Set a MINSIZE of the window (roughly). ## ## For WIDTH, allow for the minwidth of the '.fRbuttons' frame: ## at least 9 widgets --- Exit, Help, etc. buttons. ## ## For HEIGHT, allow ## about 1 char high for the '.fRbuttons' frame and entry frames ## below that frame, ## about 24 pixels high for the '.fRplot' frame. ##+################################################################### set minWinWidthPx [font measure fontTEMP_varwidth \ "$aRtext(buttonEXIT) $aRtext(buttonHELP) \ $aRtext(chkbuttLINES) $aRtext(chkbuttBORDER) \ $aRtext(buttonCANCOLOR) $aRtext(buttonIMG) \ $aRtext(buttonUPDATE) \ $aRtext(buttonDWNCAN) $aRtext(buttonUPCAN) \ $aRtext(buttonPRINT) $aRtext(buttonPRTPREVIEW)"] ## Add some pixels to account for right-left-side window decoration ## (about 8 pixels), and about 9 x 4 pixels/widget for borders/padding ## for at least 9 button widgets. set minWinWidthPx [expr {44 + $minWinWidthPx}] ## MIN HEIGHT --- ## for the 7 stacked frames allow ## 1 char high for 'fRbuttons' ## 1 char high for 'fRtitle_main' ## 1 char high for 'fRtitle_xy' ## 1 char high for 'fRlims_xy' ## 1 char high for 'fRvals_x' ## 1 char high for 'fRvals_y' ## 24 pixels high for 'fRplot'. set CharHeightPx [font metrics fontTEMP_varwidth -linespace] set minWinHeightPx [expr {6 * $CharHeightPx}] set minWinHeightPx [expr {$minWinHeightPx + 24}] ## Add about 28 pixels for top-bottom window decoration, ## about 7x4 pixels for each of the 7 stacked frames and their ## widgets (their borders/padding). set minWinHeightPx [expr {$minWinHeightPx + 56}] ## FOR TESTING: # puts "minWinWidthPx = $minWinWidthPx" # puts "minWinHeightPx = $minWinHeightPx" wm minsize . $minWinWidthPx $minWinHeightPx ## We allow the window to be resizable and we pack the canvas with ## '-fill both -expand 1' so that the canvas can be enlarged by enlarging ## the window. ## If you want to make the window un-resizable, ## you can use the following statement. # wm resizable . 0 0 ##+#################################################################### ##+#################################################################### ## DEFINE *ALL* THE FRAMES -- (top to bottom): ## ## - 'fRbuttons' contains buttons -- ## Exit, Help, UpdatePlot, etc. buttons. ## ## - 'fRtitle_main' contains 1 label & 1 entry widget. ## - 'fRtitles_xy' contains 2 pairs of label & entry widgets. ## - 'fRlims_xy' contains 4 pairs of label & entry widgets. ## - 'fRvals_x' contains 1 label & 1 entry widget. ## - 'fRvals_y' contains 1 label & 1 entry widget. ## - 'fRlow' contains 2 side-by-side sub-frames. ## ## Then the sub-frames: ## - '.fRlow.fRmsg' contains a mini-guide in a text or label widget. ## - '.fRlow.fRplot' contains a canvas widget. ## ##+#################################################################### ## FOR TESTING change 0 to 1: ## (Example1: To see appearance of frames when borders are drawn.) ## (Example2: To see sizes of frames for various '-fill' options.) ## (Example3: To see how frames expand as window is resized.) if {0} { set RELIEF_frame raised set BDwidthPx_frame 2 } else { set RELIEF_frame flat set BDwidthPx_frame 0 } frame .fRbuttons -relief $RELIEF_frame -bd $BDwidthPx_frame frame .fRtitle_main -relief $RELIEF_frame -bd $BDwidthPx_frame frame .fRtitles_xy -relief $RELIEF_frame -bd $BDwidthPx_frame frame .fRlims_xy -relief $RELIEF_frame -bd $BDwidthPx_frame frame .fRvals_x -relief $RELIEF_frame -bd $BDwidthPx_frame frame .fRvals_y -relief $RELIEF_frame -bd $BDwidthPx_frame frame .fRlow -relief $RELIEF_frame -bd $BDwidthPx_frame frame .fRlow.fRmsg -relief raised -bd 2 frame .fRlow.fRplot -relief raised -bd 2 ##+######################################################## ## PACK *ALL* the FRAMES. ##+######################################################## ## PACK THE FRAMES SEPARATELY, in order to facilitate ## experiments with different behaviors in window expansion. ##+######################################################## pack .fRbuttons \ -side top \ -anchor w \ -fill x \ -expand 0 pack .fRtitle_main \ -side top \ -anchor w \ -fill x \ -expand 0 pack .fRtitles_xy \ -side top \ -anchor w \ -fill x \ -expand 0 pack .fRlims_xy \ -side top \ -anchor w \ -fill x \ -expand 0 pack .fRvals_x \ -side top \ -anchor w \ -fill x \ -expand 0 pack .fRvals_y \ -side top \ -anchor w \ -fill x \ -expand 0 pack .fRlow \ -side top \ -anchor center \ -fill both \ -expand 1 pack .fRlow.fRmsg \ -side left \ -anchor nw \ -fill y \ -expand 0 pack .fRlow.fRplot \ -side right \ -anchor ne \ -fill both \ -expand 1 ##+################################################################ ## Finished defining all the frames. ##+################################################################ ## START DEFINING & PACKING WIDGETS WITHIN THEIR FRAMES. ##+################################################################ ##+################################################################ ##+############################################################ ## IN THE 'fRbuttons' frame -- DEFINE at least 9 BUTTON WIDGETs. ## THEN PACK THEM. ##+############################################################ button .fRbuttons.buttExit \ -text "$aRtext(buttonEXIT)" \ -font fontTEMP_button \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief $RELIEF_button \ -command {exit} button .fRbuttons.buttHelp \ -text "$aRtext(buttonHELP)" \ -font fontTEMP_button \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief $RELIEF_button \ -command {popup_msgVarWithScroll .topHelp "$HELPtext" +10+10} button .fRbuttons.buttCanvasColor \ -text "$aRtext(buttonCANCOLOR)" \ -font fontTEMP_button \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief $RELIEF_button \ -command {getSet_canvasColor} button .fRbuttons.buttUpdate \ -text "$aRtext(buttonUPDATE)" \ -font fontTEMP_button \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief $RELIEF_button \ -command {update_plot} ## The checkbutton variable, Lines0or1, will be initialized ## in the 'Additional GUI Initialization' section at the bottom of ## this Tk script. Example: ## set Lines0or1 0 checkbutton .fRbuttons.chkbuttLines \ -variable Lines0or1 \ -selectcolor "$chkbuttBKGD" \ -text "$aRtext(chkbuttLINES)" \ -font fontTEMP_SMALL_chkbutt \ -padx $PADXpx_chkbutt \ -pady $PADYpx_chkbutt \ -bd $BDwidthPx_chkbutt \ -relief $RELIEF_chkbutt ## The checkbutton variable, Border0or1, will be initialized ## in the 'Additional GUI Initialization' section at the bottom of ## this Tk script. Example: ## set Border0or1 0 checkbutton .fRbuttons.chkbuttBorder \ -variable Border0or1 \ -selectcolor "$chkbuttBKGD" \ -text "$aRtext(chkbuttBORDER)" \ -font fontTEMP_SMALL_chkbutt \ -padx $PADXpx_chkbutt \ -pady $PADYpx_chkbutt \ -bd $BDwidthPx_chkbutt \ -relief $RELIEF_chkbutt ## Could implement Apply-image/logo option someday. if {1} { button .fRbuttons.buttImg \ -text "$aRtext(buttonIMG)" \ -font fontTEMP_button \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief $RELIEF_button \ -command {getPut_image} } button .fRbuttons.buttDWNwin \ -text "$aRtext(buttonDWNCAN)" \ -font fontTEMP_button \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief $RELIEF_button \ -command {downsize_canvas} button .fRbuttons.buttUPwin \ -text "$aRtext(buttonUPCAN)" \ -font fontTEMP_button \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief $RELIEF_button \ -command {upsize_canvas} button .fRbuttons.buttPrint \ -text "$aRtext(buttonPRINT)" \ -font fontTEMP_button \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief $RELIEF_button \ -command {print_plot} button .fRbuttons.buttPrtPreview \ -text "$aRtext(buttonPRTPREVIEW)" \ -font fontTEMP_button \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief $RELIEF_button \ -command {print_preview} label .fRbuttons.labPRTCMD \ -text "$aRtext(labelPRINTCMD)" \ -font fontTEMP_label \ -justify left \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## We initialize this var at the bottom of this script, ## in the GUI inititalization section. Example: # set ENTRYprintcmd "$PRINTcmd" entry .fRbuttons.entPRTCMD \ -textvariable ENTRYprintcmd \ -width 25 \ -font fontTEMP_entry \ -bg $entryBKGD \ -bd $BDwidthPx_entry \ -relief $RELIEF_entry ## Pack the widgets in frame '.fRbuttons'. ## (We might want to change the order someday.) pack .fRbuttons.buttExit \ .fRbuttons.buttHelp \ .fRbuttons.chkbuttLines \ .fRbuttons.chkbuttBorder \ -side left \ -anchor w \ -fill none \ -expand 0 ## Could implement Apply-image/logo option someday. if {1} { pack .fRbuttons.buttImg \ -side left \ -anchor w \ -fill none \ -expand 0 } pack .fRbuttons.buttUpdate \ .fRbuttons.buttCanvasColor \ .fRbuttons.buttDWNwin \ .fRbuttons.buttUPwin \ .fRbuttons.buttPrtPreview \ .fRbuttons.buttPrint \ .fRbuttons.labPRTCMD \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRbuttons.entPRTCMD \ -side left \ -anchor w \ -fill x \ -expand 1 ##+######################################################## ## IN THE 'fRtitle_main' frame -- ## DEFINE 1 LABEL & 1 ENTRY WIDGET. THEN PACK EM. ##+######################################################## label .fRtitle_main.labPlotTitle \ -text "$aRtext(labelPLOTTITLE)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## We initialize this var at the bottom of this script, ## in the GUI inititalization section. Example: # set ENTRYtitleMain " MAIN PLOT TITLE here." entry .fRtitle_main.entPlotTitle \ -textvariable ENTRYtitleMain \ -width 75 \ -font fontTEMP_entry \ -bg $entryBKGD \ -bd $BDwidthPx_entry \ -relief $RELIEF_entry ## Pack the widgets in frame '.fRtitle_main'. pack .fRtitle_main.labPlotTitle \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRtitle_main.entPlotTitle \ -side left \ -anchor w \ -fill x \ -expand 1 ##+######################################################## ## IN THE 'fRtitles_xy' frame -- ## DEFINE 2 pairs of LABEL & ENTRY widgets for x-axis & y-axis. ## THEN PACK the 4 widgets. ##+######################################################## label .fRtitles_xy.labXaxisTitle \ -text "$aRtext(labelXAXISTITLE)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## We initialize this var at the bottom of this script, ## in the GUI inititalization section. Example: # set ENTRYtitleXaxis " X-AXIS TITLE here." entry .fRtitles_xy.entXaxisTitle \ -textvariable ENTRYtitleXaxis \ -width 40 \ -font fontTEMP_entry \ -bg $entryBKGD \ -bd $BDwidthPx_entry \ -relief $RELIEF_entry label .fRtitles_xy.labYaxisTitle \ -text "$aRtext(labelYAXISTITLE)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## We initialize this var at the bottom of this script, ## in the GUI inititalization section. Example: # set ENTRYtitleYaxis " Y-AXIS TITLE here. " entry .fRtitles_xy.entYaxisTitle \ -textvariable ENTRYtitleYaxis \ -width 40 \ -font fontTEMP_entry \ -bg $entryBKGD \ -bd $BDwidthPx_entry \ -relief $RELIEF_entry ## Pack the widgets in frame '.fRtitles_xy'. pack .fRtitles_xy.labXaxisTitle \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRtitles_xy.entXaxisTitle \ -side left \ -anchor w \ -fill x \ -expand 1 pack .fRtitles_xy.labYaxisTitle \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRtitles_xy.entYaxisTitle \ -side left \ -anchor w \ -fill x \ -expand 1 ##+######################################################## ## IN THE 'fRlims_xy' frame -- ## DEFINE 6 pairs of LABEL & ENTRY widgets --- for ## x-axis min & max &tic-dist and ## y-axis min & max & tic-dist. ## THEN PACK the 12 widgets. ##+######################################################## set entWIDTHchars 8 label .fRlims_xy.labXaxisMIN \ -text "$aRtext(labelXAXISMIN)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## We initialize this var at the bottom of this script, ## in the GUI inititalization section. Examples: # set ENTRYxaxismin "0" # set ENTRYxaxismin "0.0" ; ## Causes tic-labels to go to 1-decimal format. entry .fRlims_xy.entXaxisMIN \ -textvariable ENTRYxaxismin \ -width $entWIDTHchars \ -font fontTEMP_entry \ -bg $entryBKGD \ -bd $BDwidthPx_entry \ -relief $RELIEF_entry label .fRlims_xy.labXaxisMAX \ -text "$aRtext(labelXAXISMAX)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## We initialize this var at the bottom of this script, ## in the GUI inititalization section. Examples: # set ENTRYxaxismax "100" # set ENTRYxaxismax "100.0" ; ## Causes tic-labels to go to 1-decimal format. entry .fRlims_xy.entXaxisMAX \ -textvariable ENTRYxaxismax \ -width $entWIDTHchars \ -font fontTEMP_entry \ -bg $entryBKGD \ -bd $BDwidthPx_entry \ -relief $RELIEF_entry label .fRlims_xy.labXticDIST \ -text "$aRtext(labelXTICDIST)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## We initialize this var at the bottom of this script, ## in the GUI inititalization section. Examples: # set ENTRYxticdist "10.0" entry .fRlims_xy.entXticDIST \ -textvariable ENTRYxticdist \ -width $entWIDTHchars \ -font fontTEMP_entry \ -bg $entryBKGD \ -bd $BDwidthPx_entry \ -relief $RELIEF_entry ## Now define the Y-AXIS min-max-ticdist widgets: label .fRlims_xy.labYaxisMIN \ -text "$aRtext(labelYAXISMIN)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## We initialize this var at the bottom of this script, ## in the GUI inititalization section. Examples: # set ENTRYyaxismin "0" # set ENTRYyaxismin "0.0" ; ## Causes tic-labels to go to 1-decimal format. entry .fRlims_xy.entYaxisMIN \ -textvariable ENTRYyaxismin \ -width $entWIDTHchars \ -font fontTEMP_entry \ -bg $entryBKGD \ -bd $BDwidthPx_entry \ -relief $RELIEF_entry label .fRlims_xy.labYaxisMAX \ -text "$aRtext(labelYAXISMAX)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## We initialize this var at the bottom of this script, ## in the GUI inititalization section. Examples: # set ENTRYyaxismax "100" # set ENTRYyaxismax "100.0" ; ## Causes tic-labels to go to 1-decimal format. entry .fRlims_xy.entYaxisMAX \ -textvariable ENTRYyaxismax \ -width $entWIDTHchars \ -font fontTEMP_entry \ -bg $entryBKGD \ -bd $BDwidthPx_entry \ -relief $RELIEF_entry label .fRlims_xy.labYticDIST \ -text "$aRtext(labelYTICDIST)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## We initialize this var at the bottom of this script, ## in the GUI inititalization section. Examples: # set ENTRYyticdist "10.0" entry .fRlims_xy.entYticDIST \ -textvariable ENTRYyticdist \ -width $entWIDTHchars \ -font fontTEMP_entry \ -bg $entryBKGD \ -bd $BDwidthPx_entry \ -relief $RELIEF_entry ## Pack the XAXISmin, XAXISmax, XticDIST widgets ## and the YAXISmin, YAXISmax, YticDIST widgets in frame '.fRlims_xy': pack .fRlims_xy.labXaxisMIN \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRlims_xy.entXaxisMIN \ -side left \ -anchor w \ -fill x \ -expand 1 pack .fRlims_xy.labXaxisMAX \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRlims_xy.entXaxisMAX \ -side left \ -anchor w \ -fill x \ -expand 1 pack .fRlims_xy.labXticDIST \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRlims_xy.entXticDIST \ -side left \ -anchor w \ -fill x \ -expand 1 pack .fRlims_xy.labYaxisMIN \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRlims_xy.entYaxisMIN \ -side left \ -anchor w \ -fill x \ -expand 1 pack .fRlims_xy.labYaxisMAX \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRlims_xy.entYaxisMAX \ -side left \ -anchor w \ -fill x \ -expand 1 pack .fRlims_xy.labYticDIST \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRlims_xy.entYticDIST \ -side left \ -anchor w \ -fill x \ -expand 1 ##+######################################################## ## IN THE 'fRvals_x' frame -- ## DEFINE 1 pair of LABEL & ENTRY widgets. THEN PACK THEM. ##+######################################################## label .fRvals_x.labXvals \ -text "$aRtext(labelXDATA)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## We initialize this var at the bottom of this script, ## in the GUI inititalization section. Example: # set ENTRYxvals "10.0 30.0 50.0 70.0 90.0" entry .fRvals_x.entXvals \ -textvariable ENTRYxvals \ -width 80 \ -font fontTEMP_entry \ -bg $entryBKGD \ -bd $BDwidthPx_entry \ -relief $RELIEF_entry ## Pack the Xvals widgets in frame '.fRvals_x': pack .fRvals_x.labXvals \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRvals_x.entXvals \ -side left \ -anchor w \ -fill x \ -expand 1 ##+######################################################## ## IN THE 'fRvals_y' frame -- ## DEFINE 1 pair of LABEL & ENTRY widgets. THEN PACK THEM. ##+######################################################## label .fRvals_y.labYvals \ -text "$aRtext(labelYDATA)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## We initialize this var at the bottom of this script, ## in the GUI inititalization section. Example: # set ENTRYyvals "10.0 30.0 50.0 70.0 90.0" entry .fRvals_y.entYvals \ -textvariable ENTRYyvals \ -width 80 \ -font fontTEMP_entry \ -bg $entryBKGD \ -bd $BDwidthPx_entry \ -relief $RELIEF_entry ## Pack the Yvals widgets in frame '.fRvals_y'. pack .fRvals_y.labYvals \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRvals_y.entYvals \ -side left \ -anchor w \ -fill x \ -expand 1 ##+######################################################## ## IN THE 'fRlow.fRmsg' frame -- DEFINE 1 LABEL WIDGET. ## THEN PACK IT. ##+######################################################## label .fRlow.fRmsg.labMSG \ -text "$aRtext(labelHELPMSG)" \ -font fontTEMP_SMALL_label \ -justify left \ -anchor nw \ -padx $PADXpx_label \ -pady $PADYpx_label \ -relief $RELIEF_label ## Pack the widget in frame '.fRlow.fRmsg'. pack .fRlow.fRmsg.labMSG \ -side top \ -anchor nw \ -fill none \ -expand 0 ##+######################################################## ## IN THE 'fRlow.fRplot' frame -- DEFINE 1 CANVAS WIDGET. ## THEN PACK IT. ## ## We set highlightthickness & borderwidth of the canvas to ## zero, as suggested on page 558, Chapter 37, 'The Canvas ## Widget', in the 4th edition of the book 'Practical ## Programming in Tcl and Tk', by Welch, Jones, Hobbs. ##+######################################################## ## Instead of hard-coding an initial canvas size, like this ## set INITcanWidthPx 500 ## set INITcanHeightPx 375 ## we set the canvas size in proportion to the screen size. set SCRNsizexPx [winfo screenwidth .] set SCRNsizeyPx [winfo screenheight .] set INITcanWidthPx [ expr {int(6 * $SCRNsizexPx / 10)} ] set INITcanHeightPx [ expr {int(6 * $SCRNsizeyPx / 10)} ] ## FOR TESTING: # puts "INITcanWidthPx: $INITcanWidthPx" # puts "INITcanHeightPx: $INITcanHeightPx" canvas .fRlow.fRplot.can \ -width $INITcanWidthPx \ -height $INITcanHeightPx \ -relief $RELIEF_canvas \ -highlightthickness 0 \ -borderwidth 0 ## Pack the widget in frame '.fRlow.fRplot'. ## Allow it to expand to fill window. Anchor at 'nw'. pack .fRlow.fRplot.can \ -side top \ -anchor nw \ -fill both \ -expand 1 ##+####################################################################### ## Finished defining widgets in all the frames. ##+####################################################################### ## END OF MAIN GUI BUILDING SECTION. ##+####################################################################### ##+####################################################################### ##+####################################################################### ##+####################################################################### ## DEFINE BINDINGS -- for mouse actions: ## - to Drag titles (and tic-mark labels and images) ## - to Change color of titles and tic-mark labels during their move ## ## NOTE: In the following, instead of using 'TAGtitles' and 'TAGimage' ## we could have used 'TAGmoveable' for any movable item, and tagged ## the moveable items with tag 'TAGmoveable' instead of 'TAGtitles' ## and 'TAGimage'. But 'TAGtitles' and 'TAGimage' may prove useful for ## other operations on titles or images. ##+####################################################################### ##+####################################################################### ##+##################################### ## To Drag titles (and tic-mark labels): ##+##################################### .fRlow.fRplot.can bind TAGtitles \ "itemSelect .fRlow.fRplot.can %x %y" bind .fRlow.fRplot.can \ "itemMove .fRlow.fRplot.can %x %y" .fRlow.fRplot.can bind TAGtitles \ ".fRlow.fRplot.can dtag TAGselected" ##+################################################################## ## To Change color of titles (and tic-mark labels) during their move: ##+################################################################## .fRlow.fRplot.can bind TAGtitles \ {.fRlow.fRplot.can itemconfig current -fill "#$textCOLORselHEX"} .fRlow.fRplot.can bind TAGtitles \ {.fRlow.fRplot.can itemconfig current -fill "#$textCOLORregHEX"} ##+#################################################### ## To Drag *image* ## (no color change during move) ##+#################################################### .fRlow.fRplot.can bind TAGimage \ "itemSelect .fRlow.fRplot.can %x %y" ## This statement is defined above, for TAGtitles. ## Should work for TAGimage also. # bind .fRlow.fRplot.can \ # "itemMove .fRlow.fRplot.can %x %y" ## Remove the 'selected' tag when button is released. .fRlow.fRplot.can bind TAGimage \ ".fRlow.fRplot.can dtag TAGselected" ##+##################################################################### ##+##################################################################### ## DEFINE PROCEDURES: ## ## Main procs: ## ## - 'update_plot' - Called by the 'UpdatePlot' button. ## Performs the plot including titles, ## axes, tic-marks, and the data-point-markers. ## ## - 'set_margins' - Called by the 'update_plot' proc. ## Sets margins around 'central plot rectangle'. ## ## - 'get_deciPlaces' - Called by the 'update_plot' proc. ## ## - 'format_deciPlaces' - Called by the 'update_plot' proc. ## ## - 'itemSelect' - Called by a ButtonPress-1 binding on the canvas. ## Selects a 'moveable' item to move by putting ## a 'TAGselected' tag on the item. ## ## - 'itemMove' - Called by a Button1-Motion binding on the canvas. ## Moves a selected item. ## ## - 'draw_lines' - Called by the 'update_plot' proc --- ## if the 'Lines' checkbutton is ON. ## Joins the data points by straight line segments. ## ## - 'draw_border' - Called by the 'update_plot' proc --- ## if the 'Border' checkbutton is ON. ## Puts a border around the plot. ## ## - 'getSet_canvasColor' - Called by the 'CanvasColor' button. ## Gets-and-sets bkgd color for canvas, ## via a separate RGB-color-selector Tk script. ## ## - 'set_plotColors' - Called by proc 'getSet_canvasColor' and at bottom ## of script to initialize canvas color and related colors. ## ## - 'invert_hexRGBcolor' - Called by proc 'set_plotColors'. ## ## - 'blackORwhite_farthestFromHexRGBcolor' - Called by proc 'set_plotColors'. ## (Alternative to 'invert_hexRGBcolor'.) ## ## - 'augment_hexRGBcolor' - Called by proc 'set_plotColors'. ## ## Other, utility procs: ## ## - 'downsize_canvas' - Called by the 'DwnCan' button. ## Reduces the GUI (and canvas) size by a fixed percentage. ## ## - 'upsize_canvas' - Called by the 'UpCan' button. ## Increases the GUI (and canvas) size by a fixed percentage. ## ## - 'resize_win' - Called by the 'downsize_canvas' and 'upsize_canvas' ## procs. ## ## - 'getPut_image' - Called by the 'GetImg' button. ## Gets and puts an image on the plot. ## ## - 'print_preview' - Called by the 'PrtPreview' button. ## Puts plot image in Postscript file and shows it to user. ## ## - 'print_plot' - Called by the 'PrtPlot' button. ## Puts plot image in Postscript file and sends to a printer. ## ## - 'popup_shortmsg' - Called by various procs --- 'update_plot' and maybe more. ## ## - 'popup_msgVarWithScroll' - Called by 'Help' button. ## Used to popup msgs, such as help, to user. ##+##################################################################### ##+##################################################################### ##+##################################################################### ## proc 'update_plot' (performs the x,y-points plot) ##+##################################################################### ## PURPOSE: To (re)create the canvas items using the current GUI entries ## where the items include titles, axes, tic-marks, data-points. ## ## METHOD: ## Uses 'create line' to create axes and tic-marks. ## Uses 'create text' for titles and tic-mark labels. ## Uses 'create oval' to mark points in the plot. ## ## Arguments: none (uses global variables declared below) ## ## CALLED BY: button .fRbuttons.buttUpdate ##+##################################################################### proc update_plot {} { ## Titles from 'entry' widgets follow. global ENTRYtitleMain ENTRYtitleYaxis ENTRYtitleXaxis ## Plot limits and data values from 'entry' widgets follow. global ENTRYxaxismax ENTRYxaxismin ENTRYxticdist global ENTRYyaxismax ENTRYyaxismin ENTRYyticdist global ENTRYxvals ENTRYyvals ## Some parms to share with proc 'draw_lines'. global NXvals NYvals ## Margins set by 'set_margins' proc follow. global MARGNleftPx MARGNrightPx MARGNtopPx MARGNbotPx ## 'Regular' colors for text (titles and tic-mark labels), lines, ## and points follow. ## ## The text and line colors are set in proc 'set_plotColors' based ## on the choice of canvas color. ## ## We may temporarily change color while a text item is being moved. ## See BINDINGS section. global textCOLORregHEX lineCOLORhex pointCOLORregHEX ## Line width global variable --- for data-point connector lines, ## axes, and tic-marks. global lineWIDTHpx ## Checkbutton variables follow. global Lines0or1 Border0or1 ## We may need to share the current canvas dimensions with other ## procs --- such as 'draw_lines' and 'draw_border'. global CURcanWidthPx CURcanHeightPx ## Some pixel parameters to be shared with proc 'draw_lines'. global XaxisMINpx PX2UNITSx YaxisBOTpx PX2UNITSy ######################################################################### ## CHECK FOR EQUAL NUMBER OF ENTRYxvals & ENTRYyvals. ######################################################################### set NXvals [ llength $ENTRYxvals ] set NYvals [ llength $ENTRYyvals ] if { $NXvals != $NYvals } { set ERRmessage "Number-of-Xvals NOT = Number-of-Yvals." set ERRtitle "Input Err" popup_shortmsg "$ERRtitle" "$ERRmessage" return } ## Make sure we are using the current canvas dimensions to ## place items on the plot canvas. set CURcanWidthPx [winfo width .fRlow.fRplot.can] set CURcanHeightPx [winfo height .fRlow.fRplot.can] ## Set some margin vars to be used to set endpoints of ## x and y axes, etc. --- in pixel units. ## (NOTE: The contents of the 'set_margins' proc may ## need to take into account, i.e. use, various ## axis-location-related 'if' statements ## in this 'update_plot' code --- further below.) set_margins ##################################################################### ## CLEAR THE CANVAS WIDGET. ##################################################################### .fRlow.fRplot.can delete all ########################################################### ## PUT MAIN TITLE NEAR TOP OF THE PLOT-CANVAS, ## anchored to the left side of the plot area. ## NOTE: The user can use leading-spaces in the plot-title ## entry field to adjust the title to the right. ########################################################### # set xPX 10 set xPX $MARGNleftPx ## Note that we are placing the text with '-anchor nw' below. ## ## We set the northwest corner of the plot-title text ## just a few pixels below the top of the canvas ## and at the left side of the 'plot rectangle' set ## in the 'set_margins' proc. set yPX 5 .fRlow.fRplot.can create text \ $xPX $yPX \ -anchor nw \ -justify center \ -text "$ENTRYtitleMain" \ -font fontTEMP_label \ -fill "#$textCOLORregHEX" \ -tags TAGtitles ########################################################### ## SET XaxisMINpx,XaxisMAXpx,YaxisTOPpx,YaxisBOTpx ## (in canvas pixels) for global use for end-points of axes. ########################################################### ## YaxisTOPpx & YaxisBOTpx refer to locations at the top and ## bottom of the canvas area. ## XaxisMINpx & XaxisMAXpx refer to locations on the left and ## right of the canvas area. ########################################################### set XaxisMINpx $MARGNleftPx set XaxisMAXpx [expr { $CURcanWidthPx - $MARGNrightPx } ] set YaxisTOPpx $MARGNtopPx set YaxisBOTpx [expr { $CURcanHeightPx - $MARGNbotPx }] ########################################################### ## We put the Y-axis title near the top of the plot, ## anchored to the left side of the plot area. ## NOTE: The user can use leading-spaces in the yaxis-title ## entry field to adjust the title to the right. ########################################################### # set xPX [expr { $MARGNleftPx + 4 } ] set xPX $MARGNleftPx ## Note that we are placing the text with '-anchor nw' below. ## ## We set the northwest corner of the yaxis-title text ## at the top of the left side of the 'plot rectangle' ## set in the 'set_margins' proc. # set yPX [expr { $MARGNtopPx - 3 }] set yPX $MARGNtopPx .fRlow.fRplot.can create text \ $xPX $yPX \ -anchor nw \ -justify left \ -text "$ENTRYtitleYaxis" \ -font fontTEMP_label \ -fill "#$textCOLORregHEX" \ -tags TAGtitles ########################################################### ## We put the X-axis title near the bottom of the plot, ## anchored to the left side of the plot area. ## NOTE: The user can use leading-spaces in the xaxis-title ## entry field to adjust the title to the right. ########################################################### # set xPX [expr { $MARGNleftPx + 4 } ] set xPX $MARGNleftPx ## Note that we are placing the text with '-anchor sw' below. ## ## We set the southwest corner of the xaxis-title text ## just a few pixels above the bottom of the canvas ## and at the left side of the 'plot rectangle' set ## in the 'set_margins' proc. # set yPX $YaxisBOTpx set yPX [expr { $CURcanHeightPx - 5 }] .fRlow.fRplot.can create text \ $xPX $yPX \ -anchor sw \ -justify left \ -text "$ENTRYtitleXaxis" \ -font fontTEMP_label \ -fill "#$textCOLORregHEX" \ -tags TAGtitles ##################################################### ## SET FACTORS THAT WILL BE USED TO ## CONVERT DATA VALS TO PIXEL COORDS. ## Units: Pixels per 'world coordinate' units. ## Data type: floating point (not integer) ##################################################### set PX2UNITSx [expr { double( $XaxisMAXpx - $XaxisMINpx ) / ( $ENTRYxaxismax - $ENTRYxaxismin ) } ] set PX2UNITSy [expr { double( $YaxisBOTpx - $YaxisTOPpx ) / ( $ENTRYyaxismax - $ENTRYyaxismin ) } ] ## FOR TESTING: # puts "PX2UNITSx: $PX2UNITSx" # puts "PX2UNITSy: $PX2UNITSy" ############################################################## ## SET X-AXIS VERTICAL LOCATION (IN PIXELS) --- in XAXISyPX. ## If ENTRYxaxismax & ENTRYxaxismin straddle 0, ## set X-axis vert-loc according to location of y=0 IN PIXELS ## --- else use YaxisBOTpx. ## ## NOTE: These kinds of checks will probably need to be ## put in the 'set_margins' proc. ############################################################## set XAXISyPX $YaxisBOTpx if { $ENTRYyaxismax > 0 && $ENTRYyaxismin < 0 } { set XAXISyPX [ expr { $YaxisBOTpx + int($PX2UNITSy * $ENTRYyaxismin) } ] } ############################################################## ## SET Y-axis horizontal location (in pixels) --- in YAXISxPX. ## If ENTRYyaxismax & ENTRYyaxismin straddle 0, ## set Y-axis horiz-loc according to location of x=0 IN PIXELS ## --- else use XaxisMINpx. ## ## NOTE: These kinds of checks will probably need to be ## put in the 'set_margins' proc. ############################################################## set YAXISxPX $XaxisMINpx if { $ENTRYxaxismax > 0 && $ENTRYxaxismin < 0 } { set YAXISxPX [ expr { $XaxisMINpx - int($PX2UNITSx * $ENTRYxaxismin) } ] } ########################################################### ## DRAW X-AXIS. ########################################################### set x0PX $XaxisMINpx set y0PX $XAXISyPX set x1PX $XaxisMAXpx set y1PX $XAXISyPX .fRlow.fRplot.can create line $x0PX $y0PX \ $x1PX $y1PX \ -width $lineWIDTHpx -capstyle round -fill "#$lineCOLORhex" ########################################################### ## DRAW enough X-AXIS TIC-MARKS to fit between X min & max ## --- and label them. ## ## These hard-coded x-axis tic-mark offsets may need to be ## set as a small percentage of the canvas height. ########################################################### # set ticOFFSETpx 15 set ticOFFSETpx 5 set xTicTopPx [expr { $y0PX - $ticOFFSETpx } ] set xTicBotPx [expr { $y0PX + $ticOFFSETpx } ] set Nxtics [expr { int ( ($ENTRYxaxismax - $ENTRYxaxismin) / $ENTRYxticdist) } ] set xTicIncrWrld $ENTRYxticdist set xTicIncrPx [expr { $PX2UNITSx * $xTicIncrWrld } ] set xDeciPlaces [get_deciPlaces "$xTicIncrWrld"] for {set i 0} {$i <= $Nxtics} {incr i} { set xPX [expr {$x0PX + ($i * $xTicIncrPx)}] .fRlow.fRplot.can create line \ $xPX $y0PX \ $xPX $xTicTopPx \ -width $lineWIDTHpx -capstyle round -fill "#$lineCOLORhex" set ticText [ format_deciPlaces [expr {$ENTRYxaxismin + ($xTicIncrWrld * $i)}] $xDeciPlaces ] .fRlow.fRplot.can create text \ $xPX $xTicBotPx \ -text $ticText \ -anchor n \ -font fontTEMP_SMALL_label \ -fill "#$textCOLORregHEX" \ -tags TAGtitles } ## END OF LOOP for {set i 0} {$i <= $Nxtics} {incr i} ########################################################### ## DRAW Y-AXIS. ########################################################### set x0PX $YAXISxPX set y0PX $YaxisBOTpx set x1PX $YAXISxPX set y1PX $YaxisTOPpx .fRlow.fRplot.can create line $x0PX $y0PX \ $x1PX $y1PX \ -width $lineWIDTHpx -capstyle round -fill "#$lineCOLORhex" ########################################################### ## DRAW enough Y-AXIS TIC-MARKS to fit between Y min & max ## --- and label them. ## ## These hard-coded y-axis tic-mark offsets may need to be ## set as a small percentage of the canvas width. ########################################################### # set ticOFFSETpx 15 set ticOFFSETpx 5 set yTicLeftPx [expr { $x0PX - $ticOFFSETpx } ] set yTicRightPx [expr { $x0PX + $ticOFFSETpx } ] set Nytics [expr { int ( ($ENTRYyaxismax - $ENTRYyaxismin) / $ENTRYyticdist) } ] set yTicIncrWrld $ENTRYyticdist set yTicIncrPx [expr { $PX2UNITSy * $yTicIncrWrld } ] set yDeciPlaces [get_deciPlaces "$yTicIncrWrld"] for {set i 0} {$i <= $Nytics} {incr i} { set yPX [expr {$y0PX - ($i*$yTicIncrPx)}] .fRlow.fRplot.can create line \ $x0PX $yPX \ $yTicRightPx $yPX \ -width $lineWIDTHpx -capstyle round -fill "#$lineCOLORhex" set ticText [ format_deciPlaces [expr {$ENTRYyaxismin + ($yTicIncrWrld * $i)}] $yDeciPlaces ] .fRlow.fRplot.can create text \ $yTicLeftPx $yPX \ -text $ticText \ -anchor e \ -justify right \ -font fontTEMP_SMALL_label \ -fill "#$textCOLORregHEX" \ -tags TAGtitles } ## END OF LOOP for {set i 0} {$i <= $Nytics} {incr i} ##################################################### ## PLOT SAMPLE DATA POINTS as small circles. ##################################################### ## Routine in 'plot.tcl' demo: ## ## foreach point {{12 56} {20 94} {33 98} {32 120} {61 180} ## {75 160} {98 223}} { ## ## set x [expr {100 + (3*[lindex $point 0])}] ## ## set y [expr {250 - (4*[lindex $point 1])/5}] ## ## set item [.fRlow.fRplot.can create oval [expr $x-6] [expr $y-6] \ ## [expr $x+6] [expr $y+6] -width 1 -outline black \ ## -fill SkyBlue2] ## ## .fRlow.fRplot.can addtag point withtag $item ## } ##################################################### ##################################################### ## SET RADIUS OF DATA MARKERS. (Circles. Could use ## squares if we accomodate a second set of y data ## or if we want to give the user a choice via ## radiobuttons or listbox or spinbox or whatever.) ##################################################### set markerRadiusPx 3 ######################################################## ## LOOP THRU X,Y DATA LISTS, CREATING DATA-POINT-MARKERS. ######################################################## for {set i 0} {$i < $NXvals} {incr i} { ## FOR TESTING: # puts "ENTRYxaxismin: $ENTRYxaxismin" # puts "Xval(i): [lindex $ENTRYxvals $i]" # puts "i: $i" set xPX [expr {$XaxisMINpx + ( $PX2UNITSx * ( [lindex $ENTRYxvals $i] - $ENTRYxaxismin ) ) } ] set yPX [expr {$YaxisBOTpx - ( $PX2UNITSy * ( [lindex $ENTRYyvals $i] - $ENTRYyaxismin ) ) } ] .fRlow.fRplot.can create oval \ [expr {$xPX - $markerRadiusPx}] [expr {$yPX - $markerRadiusPx}] \ [expr {$xPX + $markerRadiusPx}] [expr {$yPX + $markerRadiusPx}] \ -outline "#$lineCOLORhex" -fill "#$pointCOLORregHEX" \ -tags TAGdataPoints \ -width 1 # -width $lineWIDTHpx } ## END OF LOOP for {set i 0} {$i < $NXvals} {incr i} ################################################################### ## If 'Lines' checkbutton is ON, draw lines connecting data-points. ## If 'Broder' checkbutton is ON, draw border. ################################################################### if {$Lines0or1 == 1} {draw_lines} if {$Border0or1 == 1} {draw_border} } ## END of proc 'update_plot' ##+##################################################################### ## proc 'set_margins' ##+##################################################################### ## PURPOSE: ## Sets 4 'MARGN' variables that can be used to consistently set the ## limits of the 'plot rectangle' within the canvas widget. ## ## The 'plot rectangle' is the area on the canvas to which we want ## to confine the plotting of the data points. ## ## (Often the X-axis will be drawn at the bottom of the 'plot rectangle' ## and the Y-axis will be drawn at the left of the 'plot rectangle' ## --- BUT NOT ALWAYS.) ## ## The 4 'MARGN' values, in pixels, are meant to be: ## ## MARGNtopPx distance between TOP side of canvas and ## TOP side of 'plot rectangle' ## MARGNleftPx distance between LEFT side of canvas and ## LEFT side of 'plot rectangle' ## MARGNrightPx distance between RIGHT side of canvas and ## RIGHT side of 'plot rectangle' ## MARGNbotPx distance between BOTTOM side of canvas and ## BOTTOM side of 'plot rectangle' ## ## (Whenever the canvas is resized, these 'MARGN' values can be ## used to resize the 'central' plot rectangle.) ## #################################### ## SPECIFICS OF THE 'plot rectangle': (top,left,right,bottom) ## ## The 'plot rectangle' is always meant to allow some margin at ## the TOP of the canvas for a plot title --- without data points ## going into the plot title. ## ## The 'plot rectangle' is typically meant to allow some margin ## at the LEFT of the canvas, for some tic-mark labels on the ## left of a vertical Y-axis --- especially when that Y-axis is ## drawn at the left of the 'plot rectangle'. ## ## The 'plot rectangle' is typically meant to allow some margin ## at the RIGHT of the canvas, for some tic-mark labels on the ## right of a vertical Y-axis --- especially when the ## Y-axis is drawn at the right of the 'plot rectangle' ## (for example at x=0 when that is the right end of the x-axis). ## ## The 'plot rectangle' is typically meant to allow some margin ## at the BOTTOM of the canvas, for some tic-mark labels on the ## bottom side of a horizontal X-axis --- especially when the ## X is drawn at the bottom of the 'plot rectangle'. ## ######################################### ## MORE SPECIFICS OF THE 'plot rectangle': (dimensions) ## ## The 'plot rectangle', horizontally, starts at one end ## of the x-axis and goes to the other end of the x-axis ## --- in other words, the horizontal dimension of the ## 'plot rectangle' is supposed to be exactly equal to ## the length of the x-axis. ## ## The 'plot rectangle', vertically, starts at one end ## of the y-axis and goes to the other end of the y-axis ## --- in other words, the vertical dimension of the ## 'plot rectangle' is supposed to be exactly equal to ## the length of the y-axis. ## ## In short, the 'plot rectangle' is the smallest rectangle ## containing the drawing of the x and y axes. ## ############################################# ## USING FONT SIZES IN SETTING 'MARGN' VALUES: ## ## The plot-titles, axis-titles, and tic-mark labels generally ## lie outside the 'plot rectangle', so these 4 'MARGN' values ## should take those items into account (allow room for them). ## (Since the plot-titles, axis-titles, and tic-mark labels in ## this app can be moved, we have a little lee-way in setting ## the margins --- but not much.) ## ## Because of the text items in the margins, the choice of fonts ## (set at top of script) can/should be used to set these 4 ## 'MARGN' values (in pixels). ## ## Note that we set these margins in 'absolute' pixel units ## rather than as 'proportionality factors' to be applied ## to the canvas dimensions. ## ## These 4 'margin values' will be used to set variables that ## will be used to define the ending points (in pixel units) ## of the plot axes within the plot canvas, ## say XaxisMINpx,XaxisMAXpx,YaxisTOPpx,YaxisBOTpx (in pixels). ##+######################################################## ## Example use: ## set XaxisMINpx $MARGNleftPx ## set XaxisMAXpx [expr { $CURcanWidthPx - $MARGNrightPx } ] ## set YaxisTOPpx $MARGNtopPx ## set YaxisBOTpx [expr { $CURcanHeightPx - $MARGNbotPx }] ##+######################################################## ## CALLED BY: the 'update_plot' proc ##+######################################################## proc set_margins {} { ## The 'MARGN' settings below assume a Y axis at the left ## of the 'plot rectangle' and an X-axis at the bottom. ## ## Eventually we will want to put in logic, like some in ## the 'update_plot' proc, to take into account situations ## like X-axis above the bottom --- even at the top --- ## and Y axis in the middle or on the right. ## The variable 'CharHeightPx' was set where the GUI window ## minsize was set, near the top of this script. Specifically: ## set CharHeightPx [font metrics fontTEMP_varwidth -linespace] ## ## But we did not set a 'CharWidthPx' variable. ## We do that here. global CharHeightPx \ MARGNleftPx MARGNrightPx MARGNtopPx MARGNbotPx set CharWidthPx [font measure fontTEMP_varwidth "W"] ## NOTE: We are setting margins (in pixels) according ## to the font being used for text on the plot --- ## irrespective of the current dimensions of the canvas. ## I.e. we are not using percentages of canvas dimensions. set MARGNleftPx [expr {4 * $CharWidthPx}] set MARGNrightPx [expr {2 * $CharWidthPx}] set MARGNtopPx [expr {2 * $CharHeightPx}] set MARGNbotPx [expr {3 * $CharHeightPx}] } ## END of proc 'set_margins' ##+##################################################################### ## 'get_deciPlaces' PROCEDURE ##+##################################################################### ## PURPOSE: Get the number of decimal places in a number string. ## ## Argument: a number string like 10.0 or 10 or 0.25 ## ## CALLED BY: the 'update_plot' proc ##+##################################################################### proc get_deciPlaces {input} { set deciPlaces [string length [lindex [split "$input" "."] 1]] return "$deciPlaces" } ## END of proc 'get_deciPlaces' ##+##################################################################### ## 'format_deciPlaces' PROCEDURE ##+##################################################################### ## PURPOSE: Format a number string to have a given number of ## decimal places. ## ## Arguments: a number string AND an integer specifying the ## number of decimal places ## ## CALLED BY: the 'update_plot' proc ##+##################################################################### proc format_deciPlaces {input places} { set FORMAT4number "%0.${places}f" set output [format "$FORMAT4number" $input] return "$output" } ## END of proc 'format_deciPlaces' ##+##################################################################### ## 'itemSelect' PROCEDURE ##+##################################################################### ## PURPOSE: ## This procedure is invoked when the mouse is pressed over one of the ## data points. It sets up a state to allow the point to be dragged ## by marking the item with the tag 'TAGselected. ## ## Arguments: ## w - The canvas window. ## x, y - The coordinates of the mouse press. ## ## CALLED BY: a binding on a window 'w', which in this ## application is always the canvas window/widget: ## .fRlow.fRplot.can bind ##+##################################################################### set lastXsel 0 set lastYsel 0 proc itemSelect {w x y} { global lastXsel lastYsel ## Delete the tag 'TAGselected' to assure that no items are ## marked with tag 'TAGselected'. $w dtag TAGselected ## Add the tag 'TAGselected' to the currently selected item. $w addtag TAGselected withtag current $w raise current set lastXsel $x set lastYsel $y } ## END of proc 'itemSelect' ##+##################################################################### ## 'itemMove' PROCEDURE ##+##################################################################### ## PURPOSE: ## This procedure is invoked during mouse motion events. ## It drags the currently selected item, which is marked by ## the tag 'TAGselected'. ## ## Arguments: ## w - The canvas window. ## x, y - The coordinates of the mouse. ## ## CALLED BY: a binding on a window 'w', which in this ## application is always the canvas window/widget: ## .fRlow.fRplot.can bind ##+##################################################################### proc itemMove {w x y} { global lastXsel lastYsel $w move TAGselected [expr {$x-$lastXsel}] [expr {$y-$lastYsel}] set lastXsel $x set lastYsel $y } ## END of proc 'itemMove' ##+##################################################################### ## proc 'draw_lines' ##+##################################################################### ## PURPOSE: To connect the data points with lines. ## ## METHOD: ## Uses 'create line' to draw straight line from one point to the next. ## Raises the datapoint images ( that were done with 'create oval') ## so that parts of them are not hidden by the lines just drawn. ## ## Arguments: none (global variables) ## ## CALLED BY: checkbutton 'Lines' ##+##################################################################### proc draw_lines {} { global ENTRYxaxismax ENTRYxaxismin ENTRYyaxismax ENTRYyaxismin \ ENTRYxvals ENTRYyvals NXvals NYvals lineWIDTHpx lineCOLORhex ## We get some pixel parameters that were set in proc 'update_plot'. global CURcanWidthPx CURcanHeightPx \ XaxisMINpx PX2UNITSx YaxisBOTpx PX2UNITSy ##################################################### ## LOOP THRU DATA LISTS, CREATING LINE SEGMENTS. ## But first set the xprev,yprev coords (in pixels). ##################################################### set xprevPX [expr {$XaxisMINpx + ( $PX2UNITSx * ( [lindex $ENTRYxvals 0] - $ENTRYxaxismin ) ) } ] set yprevPX [expr {$YaxisBOTpx - ( $PX2UNITSy * ( [lindex $ENTRYyvals 0] - $ENTRYyaxismin ) ) } ] for {set i 1} {$i < $NXvals} {incr i} { ## FOR TESTING: # puts "ENTRYxaxismin: $ENTRYxaxismin" # puts "Xval(i): [lindex $ENTRYxvals $i]" # puts "i: $i" set xPX [expr {$XaxisMINpx + ( $PX2UNITSx * ( [lindex $ENTRYxvals $i] - $ENTRYxaxismin ) ) } ] set yPX [expr {$YaxisBOTpx - ( $PX2UNITSy * ( [lindex $ENTRYyvals $i] - $ENTRYyaxismin ) ) } ] .fRlow.fRplot.can create line \ $xprevPX $yprevPX \ $xPX $yPX \ -width $lineWIDTHpx -fill "#$lineCOLORhex" \ -tags TAGdataLines set xprevPX $xPX set yprevPX $yPX } ## END OF LOOP for {set i 1} {$i < $NXvals} {incr i} ##################################################### ## RAISE DATA-POINT IMAGES ABOVE DATA-LINE IMAGES. ## (We could pause before doing the raise, to indicate ## it is being done --- i.e. it is really optional.) ##################################################### # after 1200 { .fRlow.fRplot.can raise TAGdataPoints } .fRlow.fRplot.can raise TAGdataPoints } ## END OF proc 'draw_lines' ##+##################################################################### ## proc 'draw_border' ##+##################################################################### ## PURPOSE: To draw a border around the edge of the canvas. ## ## METHOD: ## Uses 'create line' to draw 4 straight lines and uses ## 'create arc' to draw 4 rounded corners. ## ## Arguments: none ## ## CALLED BY: button .fRbuttons.buttBorder ##+##################################################################### proc draw_border {} { ## Get current canvas dimensions, set in 'update_plot' proc. global CURcanWidthPx CURcanHeightPx lineCOLORhex lineWIDTHpx ################################################# ## Set border limits. ################################################# set BDxminPx [expr { int(0.01 * $CURcanWidthPx) } ] set BDxmaxPx [expr { int(0.99 * $CURcanWidthPx) } ] set BDytopPx [expr { int(0.01 * $CURcanHeightPx) }] set BDybotPx [expr { int(0.99 * $CURcanHeightPx) }] ################################################# ## Set corner arc radius. ################################################# set minDim $CURcanWidthPx if { $minDim > $CURcanHeightPx } { set minDim $CURcanHeightPx } set BDradPx [expr { 0.03 * $minDim } ] ################################################# ## Draw the four border lines (left,right,top,bot). ################################################# .fRlow.fRplot.can create line \ $BDxminPx [expr { $BDytopPx + $BDradPx } ] \ $BDxminPx [expr { $BDybotPx - $BDradPx } ] \ -width $lineWIDTHpx -fill "#$lineCOLORhex" \ -tags TAGborder .fRlow.fRplot.can create line \ $BDxmaxPx [expr { $BDytopPx + $BDradPx } ] \ $BDxmaxPx [expr { $BDybotPx - $BDradPx } ] \ -width $lineWIDTHpx -fill "#$lineCOLORhex" \ -tags TAGborder .fRlow.fRplot.can create line \ [expr { $BDxminPx + $BDradPx } ] $BDytopPx \ [expr { $BDxmaxPx - $BDradPx } ] $BDytopPx \ -width $lineWIDTHpx -fill "#$lineCOLORhex" \ -tags TAGborder .fRlow.fRplot.can create line \ [expr { $BDxminPx + $BDradPx } ] $BDybotPx \ [expr { $BDxmaxPx - $BDradPx } ] $BDybotPx \ -width $lineWIDTHpx -fill "#$lineCOLORhex" \ -tags TAGborder ################################################# ## Draw the four border arcs (UL,UR,LR,LL). ################################################# .fRlow.fRplot.can create arc \ $BDxminPx $BDytopPx \ [expr { $BDxminPx + 2*$BDradPx } ] [expr { $BDytopPx + 2*$BDradPx } ] \ -start 90 \ -extent 90 \ -style arc -width $lineWIDTHpx -fill "#$lineCOLORhex" \ -tags TAGborder .fRlow.fRplot.can create arc \ $BDxmaxPx $BDytopPx \ [expr { $BDxmaxPx - 2*$BDradPx } ] [expr { $BDytopPx + 2*$BDradPx } ] \ -start 0 \ -extent 90 \ -style arc -width $lineWIDTHpx -fill "#$lineCOLORhex" \ -tags TAGborder .fRlow.fRplot.can create arc \ $BDxmaxPx $BDybotPx \ [expr { $BDxmaxPx - 2*$BDradPx } ] [expr { $BDybotPx - 2*$BDradPx } ] \ -start 270 \ -extent 90 \ -style arc -width $lineWIDTHpx -fill "#$lineCOLORhex" \ -tags TAGborder .fRlow.fRplot.can create arc \ $BDxminPx $BDybotPx \ [expr { $BDxminPx + 2*$BDradPx } ] [expr { $BDybotPx - 2*$BDradPx } ] \ -start 180 \ -extent 90 \ -style arc -width $lineWIDTHpx -fill "#$lineCOLORhex" \ -tags TAGborder } ## END of proc 'draw_border' ##+##################################################################### ## proc 'getSet_canvasColor' ##+##################################################################### ## PURPOSE: Gets an RGB hex-color value (via a GUI with 3 RGB slider bars). ## The user uses the RGB color-selector GUI to select a color. ## ## Then sets the canvas 'bg' (background) to that color. ## ## NOTE: We always expect hex-color variables to hold the color in a ## form like 'ffffff' rather than '#ffffff'. We will supply the ## '#' wherever we use the hex-color variable. ## ## Arguments: none ## ## CALLED BY: the 'CanvasColor' button ##+##################################################################### proc getSet_canvasColor {} { global CANr255 CANg255 CANb255 RGBcolorSelectorScript ## FOR TESTING: # puts "CANr255: $CANr255" # puts "CANg255: $CANg255" # puts "CANb255: $CANb255" set TEMPrgb [ exec $RGBcolorSelectorScript $CANr255 $CANg255 $CANb255] ## FOR TESTING: # puts "TEMPrgb: $TEMPrgb" if { "$TEMPrgb" == "" } { return } ## Script 'sho_colorvals_via_sliders3rgb.tk' puts out 4 strings ## of the form 'r255 g255 b255 hexRGB' where the ## first 3 are integers (0-255) and the last is a 6-char hex RGB code. scan $TEMPrgb "%s %s %s %s" CANr255 CANg255 CANb255 hexRGB ## FOR TESTING: # puts "PROC 'getSet_canvasColor' :" # puts "TEMPrgb: $TEMPrgb" # puts "CANr255: $CANr255" # puts "CANg255: $CANg255" # puts "CANb255: $CANb255" ## Set the canvas background color and 'related' plot colors. set_plotColors "$hexRGB" ## Update the plot to apply the new colors. # update update_plot } ## END OF proc 'getSet_canvasColor' ##+##################################################################### ## proc 'set_plotColors' ##+##################################################################### ## PURPOSE: ## For a given hex RGB color, set the canvas background color ## and set 'related' (global) color variables: ## lineCOLORhex ## textCOLORregHEX ## textCOLORselHEX ## 'reg' = regular ; 'sel' = selected ## ## Argument: a hex RGB color string, like 'ff9933' ## ## CALLED BY: proc 'getSet_canvasColor' and at bottom of this script, in ## the 'Additional GUI Initialization' section, to ## initialize canvas color and related colors. ##+##################################################################### proc set_plotColors {hexRGBcolor} { global lineCOLORhex textCOLORregHEX textCOLORselHEX pointCOLORregHEX ############################################ ## Apply the color to the canvas background. ############################################ .fRlow.fRplot.can configure -bg "#$hexRGBcolor" ##+########################################### ## SET COLORS FOR CANVAS LINE and TEXT ITEMS. ## 'reg' = regular ; 'sel' = selected ## ## For line and text colors, we can use a choice ## of procs --- such as ## 'invert_hexRGBcolor' or ## 'blackORwhite_farthestFromHexRGBcolor' ## ## For the 'sel' text color, we want a color ## distinct from the 'reg' color. We use an ## 'augment_hexRGBcolor' proc. ##+########################################### # set lineCOLORhex [invert_hexRGBcolor "$hexRGBcolor"] set lineCOLORhex [blackORwhite_farthestFromHexRGBcolor "$hexRGBcolor"] # set textCOLORregHEX [invert_hexRGBcolor "$hexRGBcolor"] set textCOLORregHEX [blackORwhite_farthestFromHexRGBcolor "$hexRGBcolor"] set textCOLORselHEX [augment_hexRGBcolor "$textCOLORregHEX"] ######################################################### ## Set color for points (interior of ovals/circles). ## ## In the 'update_plot' proc, the outline of the circles ## is drawn with $lineCOLORhex. For some contrast, we ## used a differentiated color, such as $textCOLORselHEX ## --- the 'selected' text color --- or the canvas color, ## which should be quite different from the line color. ######################################################### ## A medium gray. # set pointCOLORregHEX "888888" # set pointCOLORregHEX "$textCOLORselHEX" set pointCOLORregHEX "$hexRGBcolor" ## FOR TESTING: if {0} { puts "PROC 'set_plotColors' :" puts "Canvas color: $hexRGBcolor" puts "Line color: $lineCOLORhex" puts "Text-regular color: $textCOLORregHEX" puts "Text-selected color: $textCOLORselHEX" puts "Point (circle) color: $pointCOLORregHEX" } } ## END OF proc 'set_plotColors' ##+##################################################################### ## proc 'invert_hexRGBcolor' ##+##################################################################### ## PURPOSE: For a given hex RGB color, invert it. ## Returns the inverted color as a hex RGB string. ## ## Argument:a hex RGB color string, like 'ff9933' ## ## CALLED BY: proc 'set_plotColors' ##+##################################################################### proc invert_hexRGBcolor {hexRGBin} { ## FOR TESTING: # puts "PROC 'invert_hexRGBcolor' :" # puts "hexRGBin: $hexRGBin" scan $hexRGBin "%2x%2x%2x" r255 g255 b255 set R255 [expr {255 - $r255}] set G255 [expr {255 - $g255}] set B255 [expr {255 - $b255}] set hexRGBout [format "%02x%02x%02x" $R255 $G255 $B255] return $hexRGBout } ## END OF proc 'invert_hexRGBcolor' ##+##################################################################### ## proc 'blackORwhite_farthestFromHexRGBcolor' ##+##################################################################### ## PURPOSE: For a given hex RGB color, returns either black or white ## --- as the hex RGB string '000000' or 'ffffff'. ## ## Argument:a hex RGB color string, like 'ff9933' ## ## CALLED BY: proc 'set_plotColors' ##+##################################################################### proc blackORwhite_farthestFromHexRGBcolor {hexRGBin} { scan $hexRGBin "%2x%2x%2x" r255 g255 b255 set tempRGBtot [expr {$r255 + $g255 + $b255}] set tempTOTlim 360 # set tempTOTlim 200 if {$tempRGBtot > $tempTOTlim} { set hexRGBout "000000" } else { set hexRGBout "ffffff" } return "$hexRGBout" } ## END OF proc 'blackORwhite_farthestFromHexRGBcolor' ##+##################################################################### ## proc 'augment_hexRGBcolor' ##+##################################################################### ## PURPOSE: For a given hex RGB color, make a color fairly distinct ## from it --- without exceeding the 0-255 limit for the ## RGB channels. ## Returns the 'augmented' color as a hex RGB string. ## ## Argument:a hex RGB color string, like 'ff9933' ## ## CALLED BY: proc 'set_plotColors' ##+##################################################################### proc augment_hexRGBcolor {hexRGBin} { scan $hexRGBin "%2x%2x%2x" r255 g255 b255 ## AUGamt should be less than half of 255, less than 127. # set AUGamt 40 set AUGamt 80 set R255 [expr {$r255 + $AUGamt}] if {$R255 > 255} { set R255 [expr {$r255 - $AUGamt}] } set G255 [expr {$g255 + $AUGamt}] if {$G255 > 255} { set G255 [expr {$g255 - $AUGamt}] } set B255 [expr {$b255 + $AUGamt}] if {$B255 > 255} { set B255 [expr {$b255 - $AUGamt}] } set hexRGBout [format "%02x%02x%02x" $R255 $G255 $B255] return $hexRGBout } ## END OF proc 'augment_hexRGBcolor' ##+##################################################################### ## proc 'downsize_canvas' ##+##################################################################### ## PURPOSE: To DOWN-size the canvas. ## ## METHOD: ## We apply a factor to the current width and height of the canvas. ## Then we call 'update_plot' to redo the plot. ## ## Actually we resize the entire GUI window and let the Tk 'pack' ## geometry manager take care of resizing the canvas appropriately ## according to the various '-fill' and '-expand' parameters for ## the widgets of the GUI. ## ## NOTE: ## The user can keep clicking the 'DwnCan' button to downsize ~5% per click. ## ## Arguments: none ## ## CALLED BY: the 'DwnCan' button ##+##################################################################### proc downsize_canvas {} { ############################################################## ## Downsize the GUI (top level) window somewhat. ############################################################## resize_win 0.95 ############################################################# ## Re-do the plot, according to the new canvas size --- which ## should be reduced because entire GUI window was reduced. ## ## The 'update' is necessary because 'update_plot' does not ## do 'update' before querying for the current canvas size. ############################################################# update update_plot } ## END OF proc 'downsize_canvas' ##+##################################################################### ## proc 'upsize_canvas' ##+##################################################################### ## PURPOSE: To UP-size the canvas. ## ## METHOD: ## We apply a factor to the current width and height of the canvas. ## Then we call 'update_plot' to redo the plot. ## ## Actually we resize the entire GUI window and let the Tk 'pack' ## geometry manager take care of resizing the canvas appropriately ## according to the various '-fill' and '-expand' parameters for ## the widgets of the GUI. ## ## NOTE: ## The user can keep clicking the 'UpCan' button to upsize ~5% per click. ## ## Arguments: none ## ## CALLED BY: the 'UpCan' button ##+##################################################################### proc upsize_canvas {} { ################################################################ ## Upsize the GUI (top level) window somewhat. ################################################################ resize_win 1.05 ########################################################### ## Re-do the plot, according to the new canvas size --- ## which should be enlarged because window was enlarged. ## ## The 'update' is necessary because 'update_plot' does not ## do 'update' before querying for the current canvas size. ########################################################### update update_plot } ## END OF proc 'upsize_canvas' ##+##################################################################### ## proc 'resize_win' ##+##################################################################### ## PURPOSE: To UP/DOWN-size the Tk window by a given factor. ## ## METHOD: Several methods could be used. ## For now, we query the top level (GUI) window width and height ## (and location) with 'wm' (rather than 'winfo') and apply the ## input argument ('factor') to the current window width and height. ## ## Then reset the window size (and location) with 'wm'. ## ## Arguments: one --- 'factor' ## ## CALLED BY: 'upsize_canvas' and 'downsize_canvas' procs ##+##################################################################### proc resize_win {factor} { ## This is not the exact window DIMENSIONS we want. ## These do not include the window decoration. # set winXlenPx [ winfo width . ] # set winYlenPx [ winfo height . ] ## FOR TESTING: # puts "FROM proc 'resize_win':" # puts "winfo-width-winXlenPx : $winXlenPx" # puts "winfo-width-winYlenPx : $winYlenPx" ## This is not the window LOCATION we want. ## It is the upper-left of the window without the window decoration. # set winXlocPx [ winfo rootx . ] # set winYlocPx [ winfo rooty . ] ## FOR TESTING: # puts "FROM proc 'resize_win':" # puts "winfo-rootx-winXlocPx : $winXlocPx" # puts "winfo-rooty-winYlocPx : $winYlocPx" ## NOTE: ## [wm geometry .] returns integers of the form ## ${winXlenPx}x${winYlenPx}+${winXlocPx}+${winYlocPx} set WMgeom [wm geometry .] set winXYlenPx [lindex [split $WMgeom '+'] 0] set winXlenPx [lindex [split $winXYlenPx 'x'] 0] set winYlenPx [lindex [split $winXYlenPx 'x'] 1] set winXlocPx [lindex [split $WMgeom '+'] 1] set winYlocPx [lindex [split $WMgeom '+'] 2] ## FOR TESTING: # puts "FROM proc 'resize_win':" # puts "wm-winXlenPx : $winXlenPx" # puts "wm-winYlenPx : $winYlenPx" # puts "wm-winXlocPx : $winXlocPx" # puts "wm-winYlocPx : $winYlocPx" ## Reduce the window size according to argument 'factor'. set winXlenPx [expr {int(floor ( $factor * $winXlenPx ))} ] set winYlenPx [expr {int(floor ( $factor * $winYlenPx ))} ] ## Adjust the 'locPx' vars for the window manager border. ## 'wm' does not account for the window decoration. ## We will have to adjust, to (try to) keep the upper-left corner ## of the window in place. set winXlocPx [ expr {$winXlocPx - 3} ] set winYlocPx [ expr {$winYlocPx - 23} ] wm geometry . ${winXlenPx}x${winYlenPx}+${winXlocPx}+${winYlocPx} } ## END OF proc 'resize_win' ##+##################################################################### ## proc 'getPut_image' ##+##################################################################### ## PURPOSE: To put one or more images (e.g. a logo) on the canvas. ## ## METHOD: ## Uses 'tk_getOpenFile' dialog to get an image filename (GIF or PNG). ## Uses Tk 'image create photo' command to create an in-memory image structure. ## Uses canvas 'create image' command to put the image on the canvas. ## ## NOTE: (on a Tk postscript limitation) ## A Tk image on a Tk canvas is not captured by the Tk canvas 'postscript' ## command. But a screen image could be captured --- in a PNG or GIF or JPEG ## file --- with a screen capture utility such as 'gnome-screenshot' --- ## for use in e-mails, web pages, or other docs. ## The screen image, in a PNG file say, could be printed with the Print ## option in a utility such as a web browser. ## ## Arguments: none ## ## CALLED BY: the 'GetImg' button ##+##################################################################### proc getPut_image {} { ## For de-activating this proc: # return ## DIRimages is set in the 'Additional GUI Initialization' section ## at the bottom of this script. global CURcanWidthPx CURcanHeightPx DIRimages set fName "" set fName [tk_getOpenFile -parent . \ -title "Select an image file (GIF or PNG)." \ -initialdir "$DIRimages" ] ## FOR TESTING: # puts "fName : $fName" if {"$fName" == ""} {return} if {[file exists "$fName"]} { ################################################ ## If the filename from the file selector exits, ## 1) create the in-memory image ## 2) put the in-memory image on the canvas ## --- near bottom-right of canvas. ############################################### set imgID [image create photo -file "$fName"] set xPx [expr { int(0.95 * $CURcanWidthPx) } ] set yPx [expr { int(0.95 * $CURcanHeightPx) }] .fRlow.fRplot.can create image \ $xPx $yPx -anchor se -image $imgID -tags TAGimage ## Could pop a message here to user letting them know ## that the image is draggable --- and that Tk ## Postscript output from a Tk canvas will not show ## the image --- and they can 'delete' the image ## by dragging it off the canvas. Alternative: ## .fRlow.fRplot.can delete TAGimage } ## END OF if {[file exists "$fName"]} } ## END of proc 'getPut_image' ##+##################################################################### ## proc 'print_preview' ##+##################################################################### ## PURPOSE: To make and view a Postscript file of the canvas image. ## ## Arguments: none ## ## CALLED BY: the 'PrtPreview' button ##+##################################################################### proc print_preview {} { global env PSviewer DIRtemp #################################################### ## Make a name of the to-be-created postscript file. #################################################### set tmp_filename "${DIRtemp}/$env(USER)_tmp_tkplot.ps" ##################################################### ## Remove a file by the same name from a previous run. ##################################################### ## It looks like we can do it without this 'eval' method. # eval exec rm -f "$tmp_filename" exec rm -f "$tmp_filename" ############################### ## Make the postscript file. ############################### .fRlow.fRplot.can postscript -file "$tmp_filename" \ -colormode color \ -pageheight 10i \ -pagewidth 7i \ -pagex 1i \ -pagey 1i \ -pageanchor sw # -colormode color # -colormode gray # -colormode monochrome ################################################ ## Show the postscript file in a viewer program. ################################################ ## It looks like we can do it without this 'eval' method. # eval exec "$PSviewer \"$tmp_filename\" &" exec $PSviewer "$tmp_filename" & ###################################################### ## We could delete the file. But leave it for the user ## in case they want to do something else with it. ###################################################### # exec rm -f "$tmp_filename" } ## END of proc 'print_preview' ##+##################################################################### ## proc 'print_plot' ##+##################################################################### ## PURPOSE: To make and send a Postscript file of the canvas image ## to a printer. ## ## Arguments: none ## ## CALLED BY: the 'Print' button ##+##################################################################### proc print_plot {} { global env PRINTcmd DIRtemp #################################################### ## Make a name of the to-be-created postscript file. #################################################### set tmp_filename "${DIRtemp}/$env(USER)_tmp_tkplot.ps" ##################################################### ## Remove a file by the same name from a previous run. ##################################################### eval exec rm -f "$tmp_filename" ################################################### ## Make the postscript file. ################################################### .fRlow.fRplot.can postscript -file "$tmp_filename" \ -colormode color \ -pageheight 10i \ -pagewidth 7i \ -pagex 1i \ -pagey 1i \ -pageanchor sw # -colormode color # -colormode gray # -colormode monochrome ################################################ ## Print the postscript file using a command ## set in the 'ADDITIONAL GUI INITIALIZATION' ## section at the bottom of this script. ################################################ eval exec $PRINTcmd "$tmp_filename" ###################################################### ## We could delete the file. But leave it for the user ## in case they want to do something else with it. ###################################################### # eval exec rm "$tmp_filename" } ## END of proc 'print_plot' ##+######################################################################## ## PROC: 'popup_shortmsg' ##+######################################################################## ## PURPOSE: Popup a short message to user --- usually a one or two ## line error message. ## ## METHOD: We can use 'tk_dialog' or we can use the ## 'popup_msgVarWithScroll' proc below. ## ## CALLED BY: various procs --- 'update_plot' and maybe more. ##+####################################################################### proc popup_shortmsg { title message } { tk_dialog .xxx "$title" "$message" warning 0 Close # popup_msgVarWithScroll .xxx "$message" +40+40 } ## END of proc 'popup_shortmsg' ##+######################################################################## ## PROC: 'popup_msgVarWithScroll' ##+######################################################################## ## PURPOSE: Report help or error conditions to the user. ## ## We do not use focus,grab,tkwait in this proc, ## because we use it to show help when the GUI is idle, ## and we may want the user to be able to keep the Help ## window open while doing some other things with the GUI ## such as putting a filename in the filename entry field ## or clicking on a radiobutton. ## ## For a similar proc with focus-grab-tkwait added, ## see the proc 'popup_msgVarWithScroll_wait' in a ## 3DterrainGeneratorExaminer Tk script. ## ## REFERENCE: page 602 of 'Practical Programming in Tcl and Tk', ## 4th edition, by Welch, Jones, Hobbs. ## ## ARGUMENTS: A toplevel frame name (such as .fRhelp or .fRerrmsg) ## and a variable holding text (many lines, if needed). ## ## CALLED BY: 'help' button ##+######################################################################## ## To have more control over the formatting of the message (esp. ## words per line), we can use this 'toplevel-text' method, rather than ## the 'tk_dialog' method -- example on page 574 of the book ## by Hattie Schroeder & Mike Doyel,'Interactive Web Applications ## with Tcl/Tk', Appendix A "ED, the Tcl Code Editor". ##+######################################################################## proc popup_msgVarWithScroll { toplevName VARtext ULloc} { ## global fontTEMP_varwidth #; Not needed. 'wish' makes these global. ## global env # bell # bell ################################################# ## Set VARwidth & VARheight from $VARtext. ################################################# ## To get VARheight, ## split at '\n' (newlines) and count 'lines'. ################################################# set VARlist [ split $VARtext "\n" ] ## For testing: # puts "VARlist: $VARlist" set VARheight [ llength $VARlist ] ## For testing: # puts "VARheight: $VARheight" ################################################# ## To get VARwidth, ## loop through the 'lines' getting length ## of each; save max. ################################################# set VARwidth 0 ############################################# ## LOOK AT EACH LINE IN THE LIST. ############################################# foreach line $VARlist { ############################################# ## Get the length of the line. ############################################# set LINEwidth [ string length $line ] if { $LINEwidth > $VARwidth } { set VARwidth $LINEwidth } } ## END OF foreach line $VARlist ## For testing: # puts "VARwidth: $VARwidth" ############################################################### ## NOTE: VARwidth works for a fixed-width font used for the ## text widget ... BUT the programmer may need to be ## careful that the contents of VARtext are all ## countable characters by the 'string length' command. ############################################################### ##################################### ## SETUP 'TOP LEVEL' HELP WINDOW. ##################################### catch {destroy $toplevName} toplevel $toplevName # wm geometry $toplevName 600x400+100+50 # wm geometry $toplevName +100+50 wm geometry $toplevName $ULloc wm title $toplevName "Note" # wm title $toplevName "Note to $env(USER)" wm iconname $toplevName "Note" ##################################### ## In the frame '$toplevName' - ## DEFINE THE TEXT WIDGET and ## its two scrollbars --- and ## DEFINE an OK BUTTON widget. ##################################### if {$VARheight > 10} { text $toplevName.text \ -wrap none \ -font fontTEMP_SMALL_fixedwidth \ -width $VARwidth \ -height $VARheight \ -bg "#f0f0f0" \ -relief raised \ -bd 2 \ -yscrollcommand "$toplevName.scrolly set" \ -xscrollcommand "$toplevName.scrollx set" ## -font fontTEMP_SMALL_varwidth scrollbar $toplevName.scrolly \ -orient vertical \ -command "$toplevName.text yview" scrollbar $toplevName.scrollx \ -orient horizontal \ -command "$toplevName.text xview" } else { text $toplevName.text \ -wrap none \ -font fontTEMP_SMALL_fixedwidth \ -width $VARwidth \ -height $VARheight \ -bg "#f0f0f0" \ -relief raised \ -bd 2 ## -font fontTEMP_SMALL_varwidth } button $toplevName.butt \ -text "OK" \ -font fontTEMP_varwidth \ -command "destroy $toplevName" ############################################### ## PACK *ALL* the widgets in frame '$toplevName'. ############################################### ## Pack the bottom button BEFORE the ## bottom x-scrollbar widget, pack $toplevName.butt \ -side bottom \ -anchor center \ -fill none \ -expand 0 if {$VARheight > 10} { ## Pack the scrollbars BEFORE the text widget, ## so that the text does not monopolize the space. pack $toplevName.scrolly \ -side right \ -anchor center \ -fill y \ -expand 0 ## DO NOT USE '-expand 1' HERE on the Y-scrollbar. ## THAT ALLOWS Y-SCROLLBAR TO EXPAND AND PUTS ## BLANK SPACE BETWEEN Y-SCROLLBAR & THE TEXT AREA. pack $toplevName.scrollx \ -side bottom \ -anchor center \ -fill x \ -expand 0 ## DO NOT USE '-expand 1' HERE on the X-scrollbar. ## THAT KEEPS THE TEXT AREA FROM EXPANDING. pack $toplevName.text \ -side top \ -anchor center \ -fill both \ -expand 1 } else { pack $toplevName.text \ -side top \ -anchor center \ -fill both \ -expand 1 } ################################################ ## Set some 'event' bindings to allow for ## easy scrolling through huge listings. ## is a press of the Page-Down key. ## is a press of the Page-Up key. ## is a press of the Home key ## to go to the top of the listing. ## is a press of the End key ## to go to the bottom of the listing. ## is a press of the Up-arrow key. ## is a press of the Down-arrow key. ################################################ bind $toplevName "$toplevName.text yview scroll +1 page" bind $toplevName "$toplevName.text yview scroll -1 page" bind $toplevName "$toplevName.text see 1.0" bind $toplevName "$toplevName.text see end" bind $toplevName "$toplevName.text yview scroll -1 unit" bind $toplevName "$toplevName.text yview scroll +1 unit" ##################################### ## LOAD MSG INTO TEXT WIDGET. ##################################### ## $toplevName.text delete 1.0 end $toplevName.text insert end $VARtext $toplevName.text configure -state disabled } ## END OF PROC 'popup_msgVarWithScroll' ##+############################################### ## END OF PROCS SECTION. ##+############################################### ## SET HELP TEXT variable. ##+############################################### set HELPtext \ "********* tkPlotQuik - Points or Line Graph Utility ********* This Tk GUI script provides an intuitive, easy-to-use X-Y-AXIS POINT-or-LINE PLOT UTILITY that can be used to make 'presentation quality' plots very QUICKLY. This Tk script presents a GUI with a canvas widget showing a 2-D point or line plot --- with titles and labels that can be dragged with the mouse. This script presents entry fields in the GUI to prompt for - x,y data - plot title - x,y axis titles - x,y axis min-max limits - x,y axis tic-mark distances. *************** OPERATING GUIDE: When the GUI first comes up, it is populated with some sample titles and some sample x,y data --- AND that data is rendered as a points-only plot in the canvas area --- or as points-with-lines, depending on the setting of the 'Lines' checkbutton variable at the bottom of the script. (You can set it as you prefer.) The title names indicate WHERE the 3 types of titles initially appear on the GUI. The user can 'drag' these 3 titles around to different places on the 'canvas' with a mouse. Just click on a title, hold down the button (button-1), and drag to a new position. Then release the button. In fact, you can 'whip' titles out-of-sight --- off an edge of the 'canvas'. If you want the titles back, you can simply click on the 'UpdatePlot' button. AND ... you can 'drag' the tic-mark labels. If you decide there are too many, you can 'whip' them off the canvas. You are not given the option to drag the data points, because you could end up with a plot that is not in 'sync' with the data shown in the 'entry' fields of the GUI. BUT you can move data points by simply changing some x or y values and then click on the 'UpdatePlot' button. The GUI could be initialized with different data and titles. At the bottom of the script --- in the 'Additional GUI Initialization' section --- there are some other sample data values that could be activated instead of this set of data. --- There are a good number of plot options. Here are some. ****************************** LINES (connecting data points): You can click on the 'Lines' checkbutton and then click on the 'UpdatePlot' button to cause lines to be drawn, connecting the data points. Turn the 'Lines' checkbutton 'off' and click 'UpdatePlot' to revert to a points-only plot. *********** PLOT BORDER: You can click on the 'Border' checkbutton and then click on the 'UpdatePlot' button to cause a border to be drawn around the plot. Turn the 'Border' checkbutton 'off' and click 'UpdatePlot' to revert to a plot without the border. *********************** CANVAS BACKGROUND COLOR: You can click on the 'CanvasColor' button and use an RGB color selector GUI that pops up to change the canvas background color. If you are going to capture the plot in an image file (such as PNG or GIF) and then print the image (say by reading the image file into a web browser and using the print capability of the web browser), you will probably want to change the plot background to WHITE --- to save on ink. Rather than make a crowded GUI more crowded by supplying buttons to set colors of text (titles and tic-mark labels) and colors of lines (data-lines, axes, tic-marks), the text and line colors are set 'automatically' based on the canvas color that is chosen. In particular, if a dark canvas color is chosen, the text and lines will be shown in a light color --- and if a light canvas color is chosen, the text and lines will be shown in a dark color. ******************************** THE 'DwnCan' and 'UpCan' BUTTONS: The 'canvas' area expands and contracts if you expand or contract the entire GUI window. One way to quickly downsize or upsize the window is to click on the 'DwnCan' or 'UpCan' button. This can be quicker than trying to get the attention of an extremely thin 'sensitive edge' of the GUI to drag the window to a different size. One thing to be aware of: The 'DwnCan' button will probably not work if the user has maximized the GUI window via the window manager 'Maximize' option or by repeated use of the 'UpCan' button. To make the 'DwnCan' button useable again, you can simply use the 'UnMaximize' ('Restore') option of the window manager. ********************************** POSTSCRIPT PREVIEW & PRINT OPTIONS: The 'PrtPreview' and the 'Print' buttons create a Postscript file in a '/tmp' directory. The 'PrtPreview' button uses a PDF/Postscript viewer utility --- such as 'evince' --- to show the Postscript file that is created. And the 'Print' button uses a print-command --- shown in an 'entry' field at the top-right of the GUI --- to send the Postscript code to a user's printer. The temporary-files-directory, the PDF/Postscript viewer-command, and the print-command can be changed by the user who downloads this script by changing 3 variables in 'set' statements at the bottom of the script in the 'Additional GUI Initialization' section: - DIRtemp - PSviewer - PRINTcmd For the print command, I found that the program '/usr/bin/cupsdoprint' of the CUPS printing system worked quite nicely --- on my Ubuntu 9.10 Linux system --- with the set of parameters seen in this code. NOTE: The Tk canvas 'postscript' option does not capture an image placed on the canvas. It captures points, curves, and text placed on the canvas. If you want to capture an image of the plot including any GIF or PNG images put on the canvas, you can use an image capture utility (such as 'gnome-screenshot') to capture the image in a PNG or GIF or JPEG file. You can crop the image with an interactive image editor (such as 'mtpaint') and then print the image file with an image-view/print utility (such as 'eog' = 'eye of gnome') or a web browser, as described above --- in the Canvas Background Color section. ******************* THE 'GetImg' BUTTON: The 'GetImg' button at the top of the GUI allows the user to get an image (like a logo) to put on the plot canvas. A file-selector GUI pops up and allows the user to select an image file (GIF or PNG) to put on the canvas. When a user selects a filename and clicks on the OK button of the file-selector, the file-selector dialog window disappears and the image appears at the lower-right of the 'canvas' area. Like for titles and tick-marks, the user can 'drag' the image from its initial placement on the canvas to anywhere else on the canvas --- and the image can be 'whipped' off of the canvas. More than one image can be fetched and placed on the canvas. ***************** THE 'Help' BUTTON: The 'Help' button on the GUI can provide more extensive help than the brief guide on the left side of the GUI. In fact, it presents this help. ********** CONCLUSION: This is a plotting-utility implementation using BASIC Tcl-Tk commands, i.e. not requiring an 'extension' of Tcl or Tk. Unfortunately, there do not seem to be any FAIRLY GENERAL, yet RELATIVELY SIMPLE, xy-point plotting scripts at Tcl-Tk archive sites --- even in 2017, more than 20 years after the development of the necessary Tk 'canvas' facilities to support plotting of lines and ovals and text and images. Nor are such GENERAL, INTERACTIVE, easy-to-use x,y point or line plotting Tk scripts available via web searches on keyword strings such as 'bin wish canvas' or 'bin wish oval' or 'bin wish line'. Even searches on 'canvas' and 'line' and 'oval' on the wiki.tcl.tk site, in early 2013, yielded only simplistic line plot 'demos' that are not suited to general and FAST point-or-line plots. There were none with entry fields for quick entry of user data and essential plot parameters. This script is meant to fill that long-time void. " ##+############################################################## ##+############################################################## ## ADDITIONAL GUI INITIALIZATION: ##+############################################################## ## - Set line-width value --- which is not currently settable via ## widgets on the GUI. (no room and too many choices already) ## ## - Set initial canvas background color and from that canvas ## color set line color (for data-lines, axes, tic-mark labels) ## and set text color (for titles and tic-mark labels). ## NOTE: ## Line and text colors are not currently settable via widgets ## on the GUI. (no room and too many choices already) ## So we set those colors 'automatically' from the canvas color. ## ## - Set some directories and helper-apps. ## ## - Set some initial 'entry' field values for a plot and ## make a plot from those entries. ##+############################################################## ##+####################################################################### ## Set line width (in pixels) --- for drawing lines connecting data points ## and axis lines and tic-mark lines. ## ## NOTE: ## Instead of hard-coding a value, we could set the width based on ## the screenwidth --- like 0.001 or 0.002 of screenwidth in pixels. ##+####################################################################### # set lineWIDTHpx 2 set SCRNsizexPx [winfo screenwidth .] # set lineWIDTHfactor 0.002 set lineWIDTHfactor 0.001 set lineWIDTHpx [expr {int($lineWIDTHfactor * $SCRNsizexPx) + 1}] ##+#################################################### ## Set an initial BACKGROUND COLOR FOR THE CANVAS --- ## and use that to set some 'related' (global) color variables: ## lineCOLORhex ## textCOLORregHEX ## textCOLORselHEX ## 'reg' = regular ; 'sel' = selected ## ## We set the canvas color a little lighter (brighter) ## than the GUI 'palette' color --- to make it stand out. ##+#################################################### set CANr255 230 set CANg255 230 set CANb255 230 set hexCOLORcan [format "%02X%02X%02X" $CANr255 $CANg255 $CANb255] set_plotColors "$hexCOLORcan" ##+#################################################### ## Set the full-name of the RGB color-selector Tk script ## that is used in one or more procs above. ##+#################################################### ## FOR TESTING: # puts "argv0: $argv0" set DIRthisScript "[file dirname $argv0]" ## For ease of testing in a Linux/Unix terminal and located at the ## directory containing this Tk script: Set the full directory name. if {"$DIRthisScript" == "."} { set DIRthisScript "[pwd]" } ## If the color selector script is in the directory with this Tk script: # set RGBcolorSelectorScript "$DIRthisScript/sho_colorvals_via_sliders3rgb.tk" ## Alternatively: If the RGB color-selector Tk script is in the ## SELECTORtools directory of the FE 'tkGooies' menu/toolchest system, ## use something like the following. set DIRupOne "[file dirname "$DIRthisScript"]" set DIRupTwo "[file dirname "$DIRupOne"]" set RGBcolorSelectorScript "$DIRupTwo/SELECTORtools/tkRGBselector/sho_colorvals_via_sliders3rgb.tk" ##+####################################################### ## Set a directory from which to get images. ## (We could put a few images in the directory with this ## Tk script --- or a lot of images in an 'images' ## subdirectory of the directory of this Tk script. ## Or use some subdirectory of the user's home directory.) ##+####################################################### # set DIRimages "$env(HOME)/Photos" # set DIRimages "${DIRthisScript}/images_GIF" # set DIRimages "${DIRthisScript}/images_PNG" set DIRimages "$DIRthisScript" ##+#################################################### ## Set a files directory for the Postscript print ## options --- 'PrtPreview' and 'Print' --- ## for a 'temporary' Postcript file. ##+#################################################### set DIRtemp "/tmp" ##+#################################################### ## Set a Postscript viewer program for use in the ## 'print_preview' proc. ##+#################################################### # set PSviewer "/usr/bin/xpdf" # set PSviewer "evince" set PSviewer "/usr/bin/evince" ##+#################################################### ## Set a print-command for use in the 'print_plot' proc. ## Show the print-command in an 'entry' widget at the ## top of the GUI. ##+#################################################### # set PRINTcmd "/usr/bin/kprinter" # set PRINTcmd "/usr/bin/hp-print" set PRINTcmd "/usr/bin/cupsdoprint -P EPSON-Epson-Stylus-NX430 -H localhost:631" set ENTRYprintcmd "$PRINTcmd" ##+#################################################### ## We can activate one of the following sets of initial ## plot settings by changing 'if {0}' to 'if {1}'. ##+#################################################### ## A generic plot example. if {1} { set ENTRYtitleMain " MAIN PLOT TITLE here." set ENTRYtitleXaxis " X-AXIS TITLE here." set ENTRYtitleYaxis " Y-AXIS TITLE here." set ENTRYxaxismin "2010" set ENTRYxaxismax "2016" set ENTRYxticdist "1" set ENTRYyaxismin "0" set ENTRYyaxismax "150" set ENTRYyticdist "10.0" set ENTRYxvals "2010 2011 2012 2013 2014 2015 2016" set ENTRYyvals "10.1 30.7 51.0 29.0 90.3 109.5 120.2" } ## END OF if {0} ## A Falkland Islands sealions' population decline plot example. if {0} { set ENTRYtitleMain " Falkland Islands - Sealions - Decline of Population" set ENTRYtitleXaxis " Year" set ENTRYtitleYaxis " Number of Sealion Pups" set ENTRYxaxismin "1900" set ENTRYxaxismax "2020" set ENTRYxticdist "30" set ENTRYyaxismin "0" set ENTRYyaxismax "8000" set ENTRYyticdist "500" set ENTRYxvals "1930 1960 1990" set ENTRYyvals "8000 500 100" } ## END OF if {0} ## A Russian population decline plot example. if {0} { set ENTRYtitleMain " Russia's Population Decline" set ENTRYtitleXaxis " Year" set ENTRYtitleYaxis " Population (millions)" set ENTRYxaxismin "1980" set ENTRYxaxismax "2020" set ENTRYxticdist "5" set ENTRYyaxismin "0" set ENTRYyaxismax "150" set ENTRYyticdist "10" set ENTRYxvals "1992 2000 2010" set ENTRYyvals "148.5 146.9 141.9" } ## END OF if {0} ## A Detroit population decline plot example. if {0} { set ENTRYtitleMain " Detroit's Population Decline" set ENTRYtitleXaxis " Year" set ENTRYtitleYaxis " Population (millions)" set ENTRYxaxismin "1870" set ENTRYxaxismax "2020" set ENTRYxticdist "10" set ENTRYyaxismin "0" set ENTRYyaxismax "2.0" set ENTRYyticdist "0.5" set ENTRYxvals "1880 1890 1900 1910 1920 1930 1940 1950 1960 1970 1980 1990 2000 2010" set ENTRYyvals "0.116 0.205 0.285 0.465 0.993 1.568 1.623 1.849 1.670 1.511 1.203 1.027 .951 .713" } ## END OF if {0} ## A Baltimore population decline plot example. if {0} { set ENTRYtitleMain " Baltimore's Population Decline" set ENTRYtitleXaxis " Year" set ENTRYtitleYaxis " Population (millions)" set ENTRYxaxismin "1940" set ENTRYxaxismax "2020" set ENTRYxticdist "10" set ENTRYyaxismin "0" set ENTRYyaxismax "1.0" set ENTRYyticdist "0.25" set ENTRYxvals "1950 1960 1970 1980 1990 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010" set ENTRYyvals "0.949 0.939 0.905 0.786 0.737 0.651 0.645 0.643 0.642 0.641 0.640 0.640 0.640 0.636 0.637 0.626" } ## END OF if {0} ## American boys 50th-percentile height plot example. if {0} { set ENTRYtitleMain " American Boys 50th-percentile Height vs Age" set ENTRYtitleXaxis " Age (years)" set ENTRYtitleYaxis " Height (cm)" set ENTRYxaxismin "0" set ENTRYxaxismax "19" set ENTRYxticdist "1" set ENTRYyaxismin "0" set ENTRYyaxismax "200" set ENTRYyticdist "10" set ENTRYxvals "0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18" set ENTRYyvals "50 75 85 94 101 108 115 121 126 132 136 142 146 152 161 168 172 173 174" } ## END OF if {0} ## World Population Growth (in millions), from year 0 to 2000. if {0} { set ENTRYtitleMain " World Population Growth" set ENTRYtitleXaxis " Year" set ENTRYtitleYaxis " Population (millions)" set ENTRYxaxismin "0" set ENTRYxaxismax "2000" set ENTRYxticdist "100" set ENTRYyaxismin "0" set ENTRYyaxismax "7000" set ENTRYyticdist "500" set ENTRYxvals " 1 200 800 1000 1100 1200 1250 1300 1400 1500 1600 1650 1700 1750 1800 1900 1910 1920 1930 1940 1950 1960 1974 1987 1999" set ENTRYyvals "170 190 220 254 301 360 400 360 350 425 545 470 600 629 813 1550 1750 1860 2070 2300 2400 3000 4000 5000 6000" } ## END OF if {0} ##+#################################################### ## Set initial values for the 2 checkbuttons. ##+#################################################### set Lines0or1 1 # set Lines0or1 0 set Border0or1 0 ##+#################################################### ## Use the current entry field settings and canvas size ## to initialize the plot area with a point or line plot. ## ## (Since 'update_plot' does not do an 'update' before ## querying the current canvas size, we need to do it here ## --- to force the 'wish' interpreter to do all the ## widget packing with the 'pack' geometry manager, ## before 'update_plot' does its thing.) ##+#################################################### update update_plot