#!/usr/bin/wish -f ## ##+####################################################################### ## NOTE: ## If the 'wish' interpreter is in another directory, like ## /usr/local/bin, you, as root, can make a soft-link from 'wish' ## in that directory to /usr/bin/wish --- with a command like ## ln -s /usr/local/bin/wish /usr/bin/wish ## The form of this command: ## ln -s ##+####################################################################### ## Tk SCRIPT NAME: tkAdsAdder.tk ##+####################################################################### ## PURPOSE: This Tk GUI script provides a GUI for adding up the ## amount of time spent on commercials (ads) during a ## TV show. ## ## Up to Nsegs commercial segments are accomodated, where ## Nsegs is about 16, but could be set higher. This is ## (hopefully) enough segments to handle half-hour and hour ## shows (such as most situation comedies and crime dramas) ## --- and even most movies shown on commercial TV. ## ## (In 2013, 'commercial segments' were typically composed of ## about 4 to 12 individual ads. The segment is/was often split into ## two 'psuedo-segments' by an annuouncer saying something like ## 'Stay tuned for ...' or 'Closed captioning is brought to you by ## after about 6 ads were presented, and then another ## 4 to 6 ads are presented. Since no real program content is ## presented during those 10 to 12 ads, the start and end time ## of the entire set of about a dozen ads should be entered --- ## i.e. treat the entire mess as one 'segment'. Who do they ## think they are kidding?) ## ##+############## ## THE GUI LAYOUT: ## ## The GUI widgets are to be laid out according to the following ## 'text-sketch' of the GUI, where ## ## - Braces indicate a Tk 'button' widget. ## - Underscores indicate a Tk 'entry' widget. ## - A colon indicates that the text before the colon is on a Tk 'label' widget. ## - Capital-O indicates a Tk 'radiobutton' widget. ## - Capital-X indicates a Tk 'checkbutton' widget. ## - A line (hyphens) with an arrow-head at each end indicates a Tk 'scale' widget. ## - Vertical bars indicate the start and end of a text line (in a Tk 'text' or 'label' widget). ## - Square brackets indicate a comment (not to be shown on the GUI). ## ## ------------------------------------------------------------------------------- ## tkAdsAdder - to add the irretrievable am't of YOUR time consumed by freakin' ads [window title] ## ------------------------------------------------------------------------------- ## {Exit} {Help} {Total-All-Ads} Total(mm:ss): |999:99| {Report} {ClearAll} ## ## Hour of Day: O AM O PM O 24-hour ## Hour: <---------------O----------------> |0-23| ## Minute: <---------------O----------------> |0-59| ## Second: <---------------O----------------> |0-59| ## {EnterStartTime} {EnterEndTime} in hh:mm:ss, in selected Segment line. ## O Ad Segment 1 Start: ______ End: ________ Length(mmm:ss): |.....| ## O Ad Segment 2 Start: ______ End: ________ Length(mmm:ss): |.....| ## O Ad Segment 3 Start: ______ End: ________ Length(mmm:ss): |.....| ## O Ad Segment 4 Start: ______ End: ________ Length(mmm:ss): |.....| ## O Ad Segment 5 Start: ______ End: ________ Length(mmm:ss): |.....| ## O Ad Segment 6 Start: ______ End: ________ Length(mmm:ss): |.....| ## O Ad Segment 7 Start: ______ End: ________ Length(mmm:ss): |.....| ## O Ad Segment 8 Start: ______ End: ________ Length(mmm:ss): |.....| ## O Ad Segment 9 Start: ______ End: ________ Length(mmm:ss): |.....| ## O Ad Segment 10 Start: ______ End: ________ Length(mmm:ss): |.....| ## O Ad Segment 11 Start: ______ End: ________ Length(mmm:ss): |.....| ## O Ad Segment 12 Start: ______ End: ________ Length(mmm:ss): |.....| ## O Ad Segment 13 Start: ______ End: ________ Length(mmm:ss): |.....| ## O Ad Segment 14 Start: ______ End: ________ Length(mmm:ss): |.....| ## O Ad Segment 15 Start: ______ End: ________ Length(mmm:ss): |.....| ## O Ad Segment 16 Start: ______ End: ________ Length(mmm:ss): |.....| ## ---------------------------------------------------------------------- ## ## This GUI will contain about: ## ## 6 'button' widgets ## 53 'label' widgets (or more) ## 32 'entry' widgets ## 3 'scale' widgets ## 19 'radiobutton' widgets ## 17 'text' (or 'label') widgets ## 0 'checkbutton' widgets ## 0 'listbox' widgets ## ##+############################### ## METHOD OF OPERATION OF THE GUI: ## ## Two entry fields are provided for each 'commercial segment' ## --- to enter start-time and end-time for each 'segment' of ads. ## ## The reason for the 3 hour/minute/second 'scale' widgets on ## the GUI is to make the entry of time (in format hh:mm:ss) ## easy for the keyboard-challenged user. ## ## The start-time and end-time are entered in hours:mins:secs, ## for each entry field. (3 radiobuttons, above the 3 'scale' widgets, ## may be used to indicate whether the user wants to specify the ## start/end time as AM or PM or 24-hour time, via the scale widgets.) ## ## Three 'scale' widgets (with slider buttons) are provided for entering ## hours, minutes, and seconds quickly by dragging the slider button ## of each of the 3 slider bars. ## ## A radiobutton is provided in front of each pair of start/end ## 'entry' widgets --- to indicate which ad-segment is being ## specified. Clicking on the 'EnterStartTime' or 'EnterEndTime' ## button then determines whether the 3 'scale' widget settings ## are put in the start or the end entry field for the ## user-specified ad-segment. ## ## After all the pairs of entry fields for a TV program are entered, ## the user can click on the 'Total-All-Ads' button, and calculations are ## performed to provide the total time consumed by all of the ads. ## ## The calculations include subtracting each end-time and start-time ## pair to get the mins:secs of each ad segment --- and then ## adding up the minutes and seconds to get the total time of the ## ads over the entire program that was watched. ## ## The total time (hrs:mins:secs or mins:secs) is displayed in a small, ## one-line text widget on the GUI. The user can copy-and-paste that time ## from this GUI to another GUI, such as a text editor GUI. ## ## A 'Report' button allows the user to generate a 'detailed' text report ## that includes all the start and end times and the differences ## that went into the total figure. ## ## The report is shown in a popup scrollable Tk text widget, ## from which the user may copy and paste the entire text into ## another window, such as a text editor or HTML editor or ## word-processor window. ## ##+######################################################################## ## 'CANONICAL' 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). ## 1b) Pack ALL the frames and sub-frames. ## 2) Define & pack all widgets in the frames, frame by frame. ## ## 3) Define key and mouse/touchpad/touch-sensitive-screen 'event' ## BINDINGS, if needed. ## 4) Define PROCS, if needed. ## 5) Additional GUI INITIALIZATION (typically with one or two ## procs in section 4), if needed. ## ##+################################# ## The code structure in more detail, for this particular script: ## ## 1a) Define ALL frames: ## ## Top-level : (top to bottom) ## 'fRbuttons' ## 'fRtimetype' ## 'fRscaleH' ## 'fRscaleM' ## 'fRscaleS' ## 'fRbuttons2' ## 'fRadseg1' ## ... ## 'fRadseg$Nsegs' ## ## Sub-frames : none ## ## 1b) Pack ALL frames, including sub-frames (if any). ## ## 2) Define & pack all widgets in the frames -- basically going through ## frames & their interiors in top-to-bottom and/or left-to-right order: ## ## 'fRbuttons' - to contain several buttons --- such as Exit, ## Help, Total-All-Ads, Report, and Clear. ## ## (Could also have a 'UseIt' button that ## returns the ads time-total to stdout, so ## this Tk script-GUI could be used to return the ## [hrs:]mins:secs to a calling script/program. ## ## 'fRtimetype' - to contain a label and several radiobuttons ## 'fRscaleH' - to contain a label and a scale widget ## 'fRscaleM' - to contain a label and a scale widget ## 'fRscaleS' - to contain a label and a scale widget ## ## 'fRbuttons2' - to contain 2 buttons and a label widget. ## ## 'fRadseg1' - to contain 1 radiobutton, 2 entry widgets, and several label widgets ## ... ... ## 'fRadseg$Nsegs' - to contain 1 radiobutton, 2 entry widgets, and several label widgets ## ## 3) Define BINDINGS: See the comments above the BINDINGS section of the ## code below, to see if any bindings were added to ## augment/facilitate the actions of the button widgets on the GUI. ## ## ## 4) Define PROCS: ## 'enterStartTime_fromScales' - called by the 'EnterStartTime' button ## 'enterEndTime_fromScales' - called by the 'EnterEndTime' button ## ## 'total_all_ads' - called by the 'Total-All-Ads' button ## 'Report' - called by the 'Report' button ## 'popup_msgVarWithScroll' - called by the 'Help' button ## ## 5) Additional GUI INITIALIZATION: none, except for setting ## the HELPtext var for the Help button. ## ##+####################################################################### ## DEVELOPED WITH: ## Tcl-Tk 8.5 on Ubuntu 9.10 (2009-october release, 'Karmic Koala'). ## ## $ wish ## % puts "$tcl_version $tk_version" ## showed 8.5 8.5 on Ubuntu 9.10 ## after Tcl-Tk 8.4 was replaced by 8.5 --- to get anti-aliased fonts. ##+######################################################################## ## MAINTENANCE HISTORY: ## Created by: Blaise Montandon 2013dec13 Started on Ubuntu 9.10. ## Changed by: Blaise Montandon 2014feb04 Finish defining the GUI. Start ## writing the procs. ## Changed by: Blaise Montandon 2014feb05 Finish writing procs. Test. ## Changed by: Blaise Montandon 2014mar10 Used 'scan' with '%d' to convert some ## hh:mm:ss text data to decimal --- to avoid ## 'invalid octal number' errors when trying ## to do arithmentic with '08' & '09'. ## ALSO: ## Made logic changes so that times between ## midnight and 1AM show as 00 hours, rather ## than 24 --- in the start-end entry fields. ## ALSO: ## Added 'RELIEF_label_lo' & 'RELIEF_numtext' ## & 'RELIEF_radbutt_hi' variables --- to be ## able to easily set the relief of some of ## the 'label'/'text'/'radiobutton' widgets --- ## so that 'label' and 'text' widgets do NOT ## look like 'button' widgets (which they did ## when they were hard-coded to 'raised') --- ## and so that 'radiobutton' widgets stand ## out as buttons to be clicked-upon. ##+############################################################################ ##+################################# ## SET THE TOP WINDOW NAME. ##+################################# wm title . \ "tkAdsAdder - adds YOUR time consumed by freakin' ads" ## - to add up the times of multiple 'commercial segments'" wm iconname . "tkAdsAdder" # catch { wm title . "$env(ADSADDER_WIN_TITLE)" } # catch { wm iconname . "$env(ADSADDER_ICON_TITLE)" } ##+################################### ## SET THE TOP WINDOW POSITION. ##+################################### wm geometry . +15+30 # catch {eval wm geometry . "$env(ADSADDER_GEOM)" } ##+####################################################################### ## SET COLOR SCHEME (palette) FOR THE WINDOW. ##+####################################################################### if {1} { ## Gray palette set Rpal255 210 set Gpal255 210 set Bpal255 210 } if {0} { ## Bluish palette set Rpal255 100 set Gpal255 0 set Bpal255 255 } if {0} { ## Greenish palette set Rpal255 160 set Gpal255 255 set Bpal255 0 } if {0} { ## Redish palette set Rpal255 255 set Gpal255 0 set Bpal255 100 } set hexCOLORpal [format "#%02X%02X%02X" $Rpal255 $Gpal255 $Bpal255] tk_setPalette $hexCOLORpal ## Set color background for some widgets. set entryBKGD "#f0f0f0" set radbuttBKGD "#f0f0f0" set scaleBKGD "#f0f0f0" set scaleBKGD "$hexCOLORpal" set textBKGD "#e0e0e0" # set chkbuttBKGD "#f0f0f0" # set listboxBKGD "#f0f0f0" ##+####################################################################### ## SET FONT VARS for use in the 'font create' statements below. ##+####################################################################### set guiFONTsize 14 set guiFONT_SMALLsize 12 ## For variable width: set FONT_varwidth \ " -family {comic sans ms} -size -$guiFONTsize -weight bold -slant roman " set FONT_SMALL_varwidth \ " -family {comic sans ms} -size -$guiFONT_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 ## For fixed width: set FONT_fixedwidth \ " -family {dejavu sans mono} -size -$guiFONTsize -weight bold -slant roman " set FONT_SMALL_fixedwidth \ " -family {dejavu sans mono} -size -$guiFONT_SMALLsize -weight normal -slant roman " ## Some other possible fixed width fonts (esp. on Linux): ## Andale Mono ## Bitstream Vera Sans Mono ## Courier 10 Pitch ## DejaVu Sans Mono ## Droid Sans Mono ## FreeMono ## Nimbus Mono L ## TlwgMono ##+##################################################################### ## DEFINE (temporary) FONT-NAMES using 'font create'. ## The font names are to be used in '-font' widget specs below. ## ## Generally we use variable-width fonts for BUTTONS and LABELS ## --- and fixed-width fonts for ENTRY and LISTBOX widgets. ## ## If we do not need to keep text columns aligned, we may ## use variable-width font in TEXT and MESSAGE widgets. ##+##################################################################### eval font create fontTEMP_button $FONT_varwidth eval font create fontTEMP_label $FONT_varwidth eval font create fontTEMP_scale $FONT_varwidth eval font create fontTEMP_varwidth $FONT_varwidth eval font create fontTEMP_entry $FONT_fixedwidth eval font create fontTEMP_listbox $FONT_fixedwidth eval font create fontTEMP_text $FONT_fixedwidth # eval font create fontTEMP_msg $FONT_fixedwidth eval font create fontTEMP_fixedwidth $FONT_fixedwidth eval font create fontTEMP_SMALL_button $FONT_SMALL_varwidth eval font create fontTEMP_SMALL_label $FONT_SMALL_varwidth eval font create fontTEMP_SMALL_varwidth $FONT_SMALL_varwidth eval font create fontTEMP_SMALL_entry $FONT_SMALL_fixedwidth eval font create fontTEMP_SMALL_listbox $FONT_SMALL_fixedwidth eval font create fontTEMP_SMALL_text $FONT_SMALL_fixedwidth # eval font create fontTEMP_SMALL_msg $FONT_SMALL_fixedwidth ##+####################################################################### ## SET GEOM VARS FOR THE VARIOUS WIDGET DEFINITIONS. ## (e.g. padx,pady for buttons) ##+####################################################################### ## For BUTTON widgets: set PADY_button 0 set PADX_button 0 set BDwidth_button 2 ## We use relief "raised" for all 'button' widgets. ## For LABEL widgets: set PADXpx_label 0 set PADYpx_label 0 set BDwidthPx_label 2 ## Relief must be flat, groove, raised, ridge, solid, or sunken. set RELIEF_label_hi "solid" set RELIEF_label_lo "flat" ## SCALE geom parameters: set BDwidthPx_scale 2 set initScaleLengthPx 300 set scaleThickPx 10 ## For ENTRY widgets: set BDwidthPx_entry 2 ## We use relief "sunken" for all 'entry' widgets. ## RADIOBUTTON widget geom settings: set PADXpx_radbutt 0 set PADYpx_radbutt 0 set BDwidthPx_radbutt 1 set RELIEF_radbutt_hi "raised" ## For TEXT widgets: set BDwidthPx_text 2 # set RELIEF_numtext "sunken" set RELIEF_numtext "ridge" # set RELIEF_numtext "groove" ##+################################################################### ## Set a MINSIZE of the window (roughly). (OR fix the window size.) ## ## For WIDTH, allow for a minwidth of the '.fRbuttons' frame: ## about 4 buttons (Exit,Help,Total-All-Ads,Report,Clear) ## and a label and text for the total. ## ## For HEIGHT, allow about ## 1 char high for the '.fRbuttons' frame ## 1 char high for the '.fRtimetype' frame ## 1 char high for the '.fRscaleH' frame ## 1 char high for the '.fRscaleM' frame ## 1 char high for the '.fRscaleS' frame ## 1 char high for the '.fRbuttons2' frame ## 1 char high for the '.fRadseg1' frame ## ... ## 1 char high for the '.fRadseg$Nsegs' frame ## --------------- ## Total 22 chars high ##+####################################################################### set minWinWidthPx [font measure fontTEMP_button \ " Exit Help Total-All-Ads Total(mm:ss) 999:99 Report Clear "] ## Add some pixels to account for right-left-side window decoration ## (about 8 pixels), about 6 widgets x 4 pixels/widget for borders/padding. set minWinWidthPx [expr {32 + $minWinWidthPx}] ## MIN HEIGHT --- about 22 chars high: set CharHeightPx [font metrics fontTEMP_button -linespace] set minWinHeightPx [expr {22 * $CharHeightPx}] ## Add about 28 pixels for top-bottom window decoration, ## about 22 frames x 4 pixels/frame for each of the 22 stacked frames ## and their widgets (their borders/padding). set minWinHeightPx [expr {116 + $minWinHeightPx}] ## FOR TESTING: # puts "minWinWidthPx = $minWinWidthPx" # puts "minWinHeightPx = $minWinHeightPx" wm minsize . $minWinWidthPx $minWinHeightPx ## If you want to make the window un-resizable, ## you can use the following statement. # wm resizable . 0 0 ## We fix the y-size of the window, but allow the x-size to vary. wm resizable . 1 0 ##+######################################################################## ## Set a TEXT-ARRAY to hold text for buttons & labels 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(buttonTOTAL) "Total-All-Ads" set aRtext(labelTOTAL) " Total(mmm:ss):" set aRtext(buttonREPORT) "Report" set aRtext(buttonCLEAR) "ClearAll" ## For '.fRtimetype' frame: set aRtext(labelTIMETYPE) "Time type:" set aRtext(radbuttAM) "AM" set aRtext(radbuttPM) "PM" set aRtext(radbutt24HR) "24-hr" set aRtext(labelTIMETYPE2) " ... for next Start/End entry." ## For '.fRscaleH' frame: set aRtext(labelHRscale) "Hour:" set aRtext(labelHRscale2) "(1-12) or (0-23)" ## For '.fRscaleM' frame: set aRtext(labelMINscale) "Minute:" set aRtext(labelMINscale2) "(0-59)" ## For '.fRscaleS' frame: set aRtext(labelSECscale) "Second:" set aRtext(labelSECscale2) "(0-59)" ## For '.fRbuttons2' frame: set aRtext(buttENTERstart) "EnterStartTime" set aRtext(buttENTERend) "EnterEndTime" set aRtext(labelSEGShead) "in hh:mm:ss (24 hr format), in selected Segment line." ## For frames '.fRadseg1' to '.fRadseg16' : set Nsegs 16 for {set k 1} {$k <= $Nsegs} {incr k} { set FMTDk [format "%02d" $k] eval set aRtext(radbuttSEGselect$k) \"AdSeg$FMTDk \" } set aRtext(labelSEGstart) "Start:" set aRtext(labelSEGend) "End:" set aRtext(labelSEGlength) " Length(mmm:ss):" ## END OF if { "$VARlocale" == "en" ##+#################################################################### ## DEFINE *ALL* THE FRAMES: ## ## TOP-LEVEL FRAMES: ## ## 'fRbuttons' - to contain buttons Exit, Help, Total-All-Ads, ## Report, Clear ## 'fRtimetype' - to contain a label and several radiobuttons ## 'fRscaleH' - to contain a label and a scale widget ## 'fRscaleM' - to contain a label and a scale widget ## 'fRscaleS' - to contain a label and a scale widget ## 'fRbuttons2' - to contain 2 buttons and a label widget. ## ## 'fRadseg1' - to contain 1 radiobutton, 2 entry widgets, ## and several label widgets ## ... ... ## ... ... ## 'fRadseg$Nsegs' - to contain 1 radiobutton, 2 entry widgets, ## and several label widgets ## ##+#################################################################### ## FOR TESTING: (esp. expansion of frames, during window expansion) # set RELIEF_frame raised # set BDwidth_frame 2 set RELIEF_frame flat set BDwidth_frame 0 frame .fRbuttons -relief $RELIEF_frame -bd $BDwidth_frame frame .fRtimetype -relief $RELIEF_frame -bd $BDwidth_frame frame .fRscaleH -relief $RELIEF_frame -bd $BDwidth_frame frame .fRscaleM -relief $RELIEF_frame -bd $BDwidth_frame frame .fRscaleS -relief $RELIEF_frame -bd $BDwidth_frame frame .fRbuttons2 -relief $RELIEF_frame -bd $BDwidth_frame # set RELIEF_frame raised # set BDwidth_frame 2 for {set k 1} {$k <= $Nsegs} {incr k} { frame .fRadseg$k -relief $RELIEF_frame -bd $BDwidth_frame } ##+######################################################## ## PACK *ALL* the FRAMES. ##+######################################################## pack .fRbuttons \ -side top \ -anchor nw \ -fill x \ -expand 0 pack .fRtimetype \ -side top \ -anchor nw \ -fill x \ -expand 0 pack .fRscaleH \ -side top \ -anchor nw \ -fill x \ -expand 0 pack .fRscaleM \ -side top \ -anchor nw \ -fill x \ -expand 0 pack .fRscaleS \ -side top \ -anchor nw \ -fill x \ -expand 0 pack .fRbuttons2 \ -side top \ -anchor nw \ -fill x \ -expand 0 for {set k 1} {$k <= $Nsegs} {incr k} { eval pack .fRadseg$k \ -side top \ -anchor nw \ -fill x \ -expand 0 } ##+################################################################ ## The frames are now defined and packed. ##+################################################################ ## START DEFINING & PACKING WIDGETS WITHIN THEIR FRAMES. ##+################################################################ ##+################################################################ ##+############################################################ ## IN THE 'fRbuttons' frame -- DEFINE BUTTONS and 1 LABEL --- ## Exit, Help, Total-All-Ads, total-label, Report, Clear ## THEN PACK THE WIDGETS. ##+############################################################ button .fRbuttons.buttEXIT \ -text "$aRtext(buttonEXIT)" \ -font fontTEMP_button \ -padx $PADX_button \ -pady $PADY_button \ -bd $BDwidth_button \ -relief raised \ -command {exit} button .fRbuttons.buttHELP \ -text "$aRtext(buttonHELP)" \ -font fontTEMP_button \ -padx $PADX_button \ -pady $PADY_button \ -bd $BDwidth_button \ -relief raised \ -command {popup_msgVarWithScroll .topHelp "$HELPtext"} button .fRbuttons.buttTOTAL \ -text "$aRtext(buttonTOTAL)" \ -font fontTEMP_button \ -padx $PADX_button \ -pady $PADY_button \ -bd $BDwidth_button \ -relief raised \ -command {total_all_ads} label .fRbuttons.labelTOTAL \ -text "$aRtext(labelTOTAL)" \ -font fontTEMP_button \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -bd $BDwidthPx_label \ -relief $RELIEF_label_lo text .fRbuttons.textTOTAL \ -font fontTEMP_text \ -height 1 \ -width 10 \ -wrap none \ -borderwidth $BDwidthPx_text \ -relief $RELIEF_numtext \ -bg $textBKGD button .fRbuttons.buttREPORT \ -text "$aRtext(buttonREPORT)" \ -font fontTEMP_button \ -padx $PADX_button \ -pady $PADY_button \ -bd $BDwidth_button \ -relief raised \ -command {Report} button .fRbuttons.buttCLEAR \ -text "$aRtext(buttonCLEAR)" \ -font fontTEMP_button \ -padx $PADX_button \ -pady $PADY_button \ -bd $BDwidth_button \ -relief raised \ -command {clear_all} ## Pack the widgets in frame '.fRbuttons'. pack .fRbuttons.buttEXIT \ .fRbuttons.buttHELP \ .fRbuttons.buttTOTAL \ .fRbuttons.labelTOTAL \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRbuttons.textTOTAL \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRbuttons.buttREPORT \ .fRbuttons.buttCLEAR \ -side right \ -anchor e \ -fill none \ -expand 0 ##+######################################################## ## IN THE 'fRtimetype' frame -- DEFINE ## a LABEL widget and AM/PM/24 RADIOBUTTONs. ## THEN PACK THEM. ##+######################################################## label .fRtimetype.labelTIMETYPE \ -text "$aRtext(labelTIMETYPE)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -bd $BDwidthPx_label \ -relief $RELIEF_label_lo radiobutton .fRtimetype.radbuttAM \ -text "$aRtext(radbuttAM)" \ -font fontTEMP_button \ -anchor w \ -variable VAR_AMorPMor24 \ -value "AM" \ -selectcolor "$radbuttBKGD" \ -padx $PADXpx_radbutt \ -pady $PADYpx_radbutt \ -bd $BDwidthPx_radbutt \ -relief $RELIEF_radbutt_hi radiobutton .fRtimetype.radbuttPM \ -text "$aRtext(radbuttPM)" \ -font fontTEMP_button \ -anchor w \ -variable VAR_AMorPMor24 \ -value "PM" \ -selectcolor "$radbuttBKGD" \ -padx $PADXpx_radbutt \ -pady $PADYpx_radbutt \ -bd $BDwidthPx_radbutt \ -relief $RELIEF_radbutt_hi radiobutton .fRtimetype.radbutt24 \ -text "$aRtext(radbutt24HR)" \ -font fontTEMP_button \ -anchor w \ -variable VAR_AMorPMor24 \ -value "24" \ -selectcolor "$radbuttBKGD" \ -padx $PADXpx_radbutt \ -pady $PADYpx_radbutt \ -bd $BDwidthPx_radbutt \ -relief $RELIEF_radbutt_hi ## Initialize the radiobutton variable. # set VAR_AMorPMor24 "AM" set VAR_AMorPMor24 "PM" # set VAR_AMorPMor24 "24" label .fRtimetype.labelTIMETYPE2 \ -text "$aRtext(labelTIMETYPE2)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -bd $BDwidthPx_label \ -relief $RELIEF_label_lo ##+######################################## ## Pack the widgets in frame 'fRtimetype'. ##+######################################## pack .fRtimetype.labelTIMETYPE \ .fRtimetype.radbuttAM \ .fRtimetype.radbuttPM \ .fRtimetype.radbutt24 \ .fRtimetype.labelTIMETYPE2 \ -side left \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE 'fRscaleH' frame -- DEFINE ## a LABEL widget and a SCALE widget and another LABEL widget. ## The scale is oriented horizontally. ## THEN PACK THEM. ##+######################################################## label .fRscaleH.label \ -text "$aRtext(labelHRscale)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -bd $BDwidthPx_label \ -relief $RELIEF_label_lo if {"$VAR_AMorPMor24" == "24"} { set HRmin 0 set HRmax 23 } else { set HRmin 1 set HRmax 12 } scale .fRscaleH.scale \ -orient horizontal \ -from $HRmin -to $HRmax \ -resolution 1 \ -digits 2 \ -length $initScaleLengthPx \ -variable VARhour \ -font fontTEMP_scale \ -showvalue true \ -bd $BDwidthPx_scale \ -relief flat \ -highlightthickness 0 \ -width $scaleThickPx \ -bg $scaleBKGD ## -command {entry_update} .fRscaleH.scale set 6 label .fRscaleH.label2 \ -text "$aRtext(labelHRscale2)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -bd $BDwidthPx_label \ -relief $RELIEF_label_lo ##+################################################# ## Pack the widgets in the frame '.fRscaleH'. ##+################################################# pack .fRscaleH.label \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRscaleH.scale \ -side left \ -anchor w \ -fill x \ -expand 1 pack .fRscaleH.label2 \ -side left \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE 'fRscaleM' frame -- DEFINE ## a LABEL widget and a SCALE widget and another LABEL widget. ## The scale is oriented horizontally. ## THEN PACK THEM. ##+######################################################## label .fRscaleM.label \ -text "$aRtext(labelMINscale)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -bd $BDwidthPx_label \ -relief $RELIEF_label_lo scale .fRscaleM.scale \ -orient horizontal \ -from 0 -to 59 \ -resolution 1 \ -digits 2 \ -length $initScaleLengthPx \ -variable VARminute \ -font fontTEMP_scale \ -showvalue true \ -bd $BDwidthPx_scale \ -relief flat \ -highlightthickness 0 \ -width $scaleThickPx \ -bg $scaleBKGD ## -command {entry_update} .fRscaleM.scale set 10 label .fRscaleM.label2 \ -text "$aRtext(labelMINscale2)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -bd $BDwidthPx_label \ -relief $RELIEF_label_lo ##+################################################# ## Pack the widgets in the frame '.fRscaleM'. ##+################################################# pack .fRscaleM.label \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRscaleM.scale \ -side left \ -anchor w \ -fill x \ -expand 1 pack .fRscaleM.label2 \ -side left \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE 'fRscaleS' frame -- DEFINE ## a LABEL widget and a SCALE widget and another LABEL widget. ## The scale is oriented horizontally. ## THEN PACK THEM. ##+######################################################## label .fRscaleS.label \ -text "$aRtext(labelSECscale)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -bd $BDwidthPx_label \ -relief $RELIEF_label_lo scale .fRscaleS.scale \ -orient horizontal \ -from 0 -to 59 \ -resolution 1 \ -digits 2 \ -length $initScaleLengthPx \ -variable VARsecond \ -font fontTEMP_scale \ -showvalue true \ -bd $BDwidthPx_scale \ -relief flat \ -highlightthickness 0 \ -width $scaleThickPx \ -bg $scaleBKGD ## -command {entry_update} .fRscaleS.scale set 30 label .fRscaleS.label2 \ -text "$aRtext(labelSECscale2)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -bd $BDwidthPx_label \ -relief $RELIEF_label_lo ##+################################################# ## Pack the widgets in the frame '.fRscaleS'. ##+################################################# pack .fRscaleS.label \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRscaleS.scale \ -side left \ -anchor w \ -fill x \ -expand 1 pack .fRscaleS.label2 \ -side left \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE 'fRbuttons2' frame -- DEFINE ## two BUTTON widgets and a LABEL widget. ## THEN PACK THEM. ##+######################################################## button .fRbuttons2.buttENTERstart \ -text "$aRtext(buttENTERstart)" \ -font fontTEMP_button \ -padx $PADX_button \ -pady $PADY_button \ -bd $BDwidth_button \ -relief raised \ -command {enterStartTime_fromScales} button .fRbuttons2.buttENTERend \ -text "$aRtext(buttENTERend)" \ -font fontTEMP_button \ -padx $PADX_button \ -pady $PADY_button \ -bd $BDwidth_button \ -relief raised \ -command {enterEndTime_fromScales} label .fRbuttons2.label \ -text "$aRtext(labelSEGShead)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -bd $BDwidthPx_label \ -relief $RELIEF_label_lo ##+################################################# ## Pack the widgets in the frame '.fRbuttons2'. ##+################################################# pack .fRbuttons2.buttENTERstart \ .fRbuttons2.buttENTERend \ .fRbuttons2.label \ -side left \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE 'fRadseg' frames --- Nsegs of them. ## In each frame, DEFINE a RADIOBUTTON widget and ## DEFINE a LABEL widget and 3 ENTRY widgets, ## for a Start time and an END time.. ## THEN PACK each set of widgets, in the loop. ##+######################################################## for {set k 1} {$k <= $Nsegs} {incr k} { radiobutton .fRadseg$k.radbutt \ -text "$aRtext(radbuttSEGselect$k)" \ -font fontTEMP_button \ -anchor w \ -variable VAR_radbutt_segnum \ -value "$k" \ -selectcolor "$radbuttBKGD" \ -padx $PADXpx_radbutt \ -pady $PADYpx_radbutt \ -bd $BDwidthPx_radbutt \ -relief $RELIEF_radbutt_hi label .fRadseg$k.labelSEGstart \ -text "$aRtext(labelSEGstart)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -bd $BDwidthPx_label \ -relief $RELIEF_label_lo set AR_24HHMMSSstart($k) "" eval entry .fRadseg$k.entrySEGstart \ -textvariable AR_24HHMMSSstart($k) \ -bg "$entryBKGD" \ -font fontTEMP_entry \ -width 8 \ -relief sunken \ -bd $BDwidthPx_entry label .fRadseg$k.labelSEGend \ -text "$aRtext(labelSEGend)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -bd $BDwidthPx_label \ -relief $RELIEF_label_lo set AR_24HHMMSSend($k) "" eval entry .fRadseg$k.entrySEGend \ -textvariable AR_24HHMMSSend($k) \ -bg $entryBKGD \ -font fontTEMP_entry \ -width 8 \ -relief sunken \ -bd $BDwidthPx_entry label .fRadseg$k.labelSEGlength \ -text "$aRtext(labelSEGlength)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -padx $PADXpx_label \ -pady $PADYpx_label \ -bd $BDwidthPx_label \ -relief $RELIEF_label_lo text .fRadseg$k.textSEGlength \ -font fontTEMP_text \ -height 1 \ -width 9 \ -wrap none \ -bd $BDwidthPx_text \ -relief $RELIEF_numtext \ -bg $textBKGD ##+################################################# ## Pack the widgets in the frame '.fRadseg$k'. ##+################################################# pack .fRadseg$k.radbutt \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRadseg$k.labelSEGstart \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRadseg$k.entrySEGstart \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRadseg$k.labelSEGend \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRadseg$k.entrySEGend \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRadseg$k.labelSEGlength \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRadseg$k.textSEGlength \ -side left \ -anchor w \ -fill none \ -expand 0 } ## END OF the LOOP to define-and-pack widgets in the frames 'fRadseg$k' ## Initialize the ad-seg-num radiobutton value. set VAR_radbutt_segnum 1 ## Set a couple of variables to use when right-justifying ## text inserted into the .fRadseg$k.textSEGlength text widgets. set FILLERtext " " set FILLERnumchars [string length "$FILLERtext"] ##+####################################### ## END OF MAIN SECTION TO SETUP THE GUI. ## FRAMES AND WIDGETS ARE DEFINED. ##+####################################### ##+####################################################################### ##+####################################################################### ## BINDINGS section: ## We could define button1-release bindings on radiobuttons OR ## the HR-MIN-SEC sliders (scales) OR bindings on entry widgets. ##+####################################################################### ##+####################################################################### bind .fRtimetype.radbuttAM { .fRscaleH.scale configure -from 1 -to 12 ## FOR TESTING: # puts "Binding on .fRtimetype.radbuttAM was triggered." } bind .fRtimetype.radbuttPM { .fRscaleH.scale configure -from 1 -to 12 ## FOR TESTING: # puts "Binding on .fRtimetype.radbuttPM was triggered." } bind .fRtimetype.radbutt24 { .fRscaleH.scale configure -from 0 -to 23 ## FOR TESTING: # puts "Binding on .fRtimetype.radbutt24 was triggered." } ##+##################################################################### ##+##################################################################### ## PROCS section: ## 'enterStartTime_fromScales' - called by the 'EnterStartTime' button. ## 'enterEndTime_fromScales' - called by the 'EnterEndTime' button. ## 'calcSEGlength_mmmss' - called by the 2 procs above, if ## both entries in the current line are ## available. ## ## 'clear_all' - clears all the start & end entry fields ## and the length and total text fields ## ## 'total_all_ads' - called by the 'Total-All-Ads' button ## 'Report' - called by the 'Report' button ## 'popup_msgVarWithScroll' - called by the 'Help' button ##+##################################################################### ##+##################################################################### ##+##################################################################### ## proc 'enterStartTime_fromScales' ##+##################################################################### ## PURPOSE: Depending on the integer, $k, in the variable 'VAR_radbutt_segnum', ## put an hh:mm:ss entry (in 24-hr time) in the Start entry field ## of entry widget .fRadseg$k.entrySEGstart --- in other words, ## put an hh:mm:ss value in array variable AR_24HHMMSSstart($k). ## ## Also: ## If both the start and end times of the $k ad-segment line ## are non-empty, calculate the length of the ad-segment ## in the form mmm:ss and put the result in the text widget ## .fRadseg$k.textSEGlength. ## ## CALLED BY: the 'EnterStartTime' button ##+##################################################################### proc enterStartTime_fromScales {} { global VAR_radbutt_segnum VAR_AMorPMor24 \ AR_24HHMMSSstart AR_24HHMMSSend ## FOR TESTING: (dummy out this proc) # return ######################################################## ## Get hour,min,sec values from the current settings of ## the hour,minute,second scales. ######################################################## set tempHR [.fRscaleH.scale get] set tempMIN [.fRscaleM.scale get] set tempSEC [.fRscaleS.scale get] ######################################################## ## Convert the hour value to 24-hour time, if the ## time-type is set to PM. ######################################################## if {"$VAR_AMorPMor24" == "PM"} { if {$tempHR < 12} { set tempHR [expr {12 + $tempHR}] } else { set tempHR 0 } } ###################################################################### ## Use the integer in the variable 'VAR_radbutt_segnum' to set $k. ## Then put an hh:mm:ss entry (in 24-hr time) in the Start entry field ## of entry widget .fRadseg$k.entrySEGstart --- in other words, ## put an hh:mm:ss value in array variable AR_24HHMMSSstart($k). ###################################################################### set k $VAR_radbutt_segnum set tempTIME \ "[format "%02d" $tempHR]:[format "%02d" $tempMIN]:[format "%02d" $tempSEC]" set AR_24HHMMSSstart($k) "$tempTIME" ############################################################ ## We have set the START time. Now if the END-time of the ## $k ad-segment line is also non-empty, ## calculate the length of the ad-segment in the form mmm:ss ## and put the result in the text widget --- ## .fRadseg$k.textSEGlength --- ## using the proc 'calcSEGlength_mmmss'. ############################################################ set tempSTRING [string trim $AR_24HHMMSSend($k)] if {"$tempSTRING" != ""} {calcSEGlength_mmmss $k} } ## END OF proc 'enterStartTime_fromScales' ##+##################################################################### ## proc 'enterEndTime_fromScales' ##+##################################################################### ## PURPOSE: Depending on the integer, $k, in the variable 'VAR_radbutt_segnum', ## put an hh:mm:ss entry (in 24-hr time) in the End entry field ## of entry widget .fRadseg$k.entrySEGend --- in other words, ## put an hh:mm:ss value in array variable AR_24HHMMSSend($k). ## ## Also: ## If both the start and end times of the $k ad-segment line ## are non-empty, calculate the length of the ad-segment ## in the form mmm:ss and put the result in the text widget ## .fRadseg$k.textSEGlength. ## ## CALLED BY: the 'EnterEndTime' button ##+##################################################################### proc enterEndTime_fromScales {} { global VAR_radbutt_segnum VAR_AMorPMor24 \ AR_24HHMMSSstart AR_24HHMMSSend ## FOR TESTING: (dummy out this proc) # return ######################################################## ## Get hour,min,sec values from the current settings of ## the hour,minute,second scales. ######################################################## set tempHR [.fRscaleH.scale get] set tempMIN [.fRscaleM.scale get] set tempSEC [.fRscaleS.scale get] ######################################################## ## Convert the hour value to 24-hour time, if the ## time-type is set to PM. ######################################################## if {"$VAR_AMorPMor24" == "PM"} { if {$tempHR < 12} { set tempHR [expr {12 + $tempHR}] } else { set tempHR 0 } } ################################################################# ## Use the integer in the variable 'VAR_radbutt_segnum' to set $k. ## Then put an hh:mm:ss entry (in 24-hr time) in the End entry field ## of entry widget .fRadseg$k.entrySEGend --- in other words, ## put an hh:mm:ss value in array variable AR_24HHMMSSend($k). ################################################################# set k $VAR_radbutt_segnum set tempTIME \ "[format "%02d" $tempHR]:[format "%02d" $tempMIN]:[format "%02d" $tempSEC]" set AR_24HHMMSSend($k) "$tempTIME" ############################################################ ## We have set the END time. Now if the START-time of the ## $k ad-segment line is also non-empty, ## calculate the length of the ad-segment in the form mmm:ss ## and put the result in the text widget --- ## .fRadseg$k.textSEGlength --- ## using the proc 'calcSEGlength_mmmss'. ############################################################ set tempSTRING [string trim $AR_24HHMMSSstart($k)] if {"$tempSTRING" != ""} {calcSEGlength_mmmss $k} } ## END OF proc 'enterEndTime_fromScales' ##+##################################################################### ## proc 'calcSEGlength_mmmss' ##+##################################################################### ## PURPOSE: If the start and end hh:mm:ss entries for a given ## ad-segment line, $k, are non-empty, this proc calculates ## the length of the ad-segment in mmm:ss format --- ## and puts the string in text widget ## .fRadseg$k.textSEGlength. ## ## CALLED BY: procs 'enterStartTime_fromScales' and ## 'enterEndTime_fromScales' ##+##################################################################### proc calcSEGlength_mmmss {k} { global VAR_radbutt_segnum FILLERtext FILLERnumchars \ AR_24HHMMSSstart AR_24HHMMSSend ## FOR TESTING: (dummy out this proc) # return ################################################# ## Get the start and end ad-segment times for the ## 'current' ad-segment line --- from the ## start and end entry fields of the current line. ################################################# ## Split out the hours, minutes, seconds (which ## should be in the form hh:mm:ss, 24-hr time) ## from the 2 entry field variables. ################################################# set STARTlist [split "$AR_24HHMMSSstart($k)" :] set ENDlist [split "$AR_24HHMMSSend($k)" :] ## FOR TESTING: # puts "IN proc 'calcSEGlength_mmmss':" # puts "STARTlist: $STARTlist" # puts "ENDlist : $ENDlist" set STARThh24 [lindex $STARTlist 0] set ENDhh24 [lindex $ENDlist 0] set STARTmm [lindex $STARTlist 1] set ENDmm [lindex $ENDlist 1] set STARTss [lindex $STARTlist 2] set ENDss [lindex $ENDlist 2] ## FOR TESTING: if {0} { puts "" puts "STARThh24: $STARThh24 ENDhh24: $ENDhh24" puts "STARTmm : $STARTmm ENDmm : $ENDmm" puts "STARTss : $STARTss ENDss : $ENDss" } ########################################################## ## If there are leading zeros on these integers, remove ## them to avoid 'invalid octal number as operand' errors ## from '08' and '09'. Ref: http://wiki.tcl.tk/15158 ########################################################## set STARThh24 [scan $STARThh24 %d] set ENDhh24 [scan $ENDhh24 %d] set STARTmm [scan $STARTmm %d] set ENDmm [scan $ENDmm %d] set STARTss [scan $STARTss %d] set ENDss [scan $ENDss %d] ## FOR TESTING: if {0} { puts "" puts "STARThh24: $STARThh24 ENDhh24: $ENDhh24" puts "STARTmm : $STARTmm ENDmm : $ENDmm" puts "STARTss : $STARTss ENDss : $ENDss" } ########################################################### ## If ENDhh24 is less than STARThh24 (for example, ENDhh24 ## is 0 and STARThh24 is 23), add 24 to ENDhh24 --- so that ## subtracting operations below do not give a negative ## number for the time difference. ######################################################## if {$ENDhh24 < $STARThh24} { set ENDhh24 [expr {$ENDhh24 + 24}] } ########################################## ## Convert start and end 'hh:mm' to 'mmm'. ########################################## set STARTmmm [expr {($STARThh24 * 60) + $STARTmm}] set ENDmmm [expr {($ENDhh24 * 60) + $ENDmm }] #################################################### ## If START 'ss' (seconds) is greater than END 'ss', ## add 60 to END 'ss' and demote the END 'mmm' by 1. #################################################### if {$STARTss > $ENDss} { set ENDss [expr {$ENDss + 60}] set ENDmmm [expr {$ENDmmm - 1}] } ######################################################### ## Calculate the difference between start and end ## 'mmm' and 'ss'. These should now both be non-negative. ######################################################### set diffMMM [expr {$ENDmmm - $STARTmmm}] set diffSS [expr {$ENDss - $STARTss }] ## FOR TESTING: if {0} { puts "" puts "ENDmmm : $ENDmmm" puts "STARTmmm: $STARTmmm" puts "diffMMM: $diffMMM" puts "" puts "ENDss : $ENDss" puts "STARTss: $STARTss" puts "diffSS : $diffSS" } ################################################### ## Set the 'mmm:ss' text string and put it in the ## text widget for the ad-segment length. ################################################### set tempLENGTH "$diffMMM:[format "%02d" $diffSS]" ######################################################### ## Insert the text string into the text widget ## for the ad-segment length --- with right justification. ######################################################### eval .fRadseg$k.textSEGlength delete 1.0 end eval .fRadseg$k.textSEGlength insert 1.0 \"$FILLERtext\" set insertIDX [expr {$FILLERnumchars - [string length "$tempLENGTH"]}] ## FOR TESTING: if {0} { puts "" puts "FILLERtext: |$FILLERtext|" puts "FILLERnumchars: $FILLERnumchars" puts "tempLENGTH: $tempLENGTH" puts "insertIDX: $insertIDX" } eval .fRadseg$k.textSEGlength insert 1.$insertIDX $tempLENGTH ######################################################### ## To help the user avoid overlaying the data in this ## ad-segment-line, advance the radiobutton variable ## value which holds the segment-number. ######################################################### set VAR_radbutt_segnum [expr {$k + 1}] } ## END OF proc 'calcSEGlength_mmmss' ##+##################################################################### ## proc 'clear_all' ##+##################################################################### ## PURPOSE: Clears all the start & end entry fields ## and the length and total text fields. ## ## CALLED BY: the 'ClearAll' button ##+#################################################################### proc clear_all {} { global Nsegs AR_24HHMMSSstart AR_24HHMMSSend ## FOR TESTING: (dummy out this proc) # return ######################################################## ## Clear the START and END entry variables in all the ## ad-segment rows, and clear the SEGlength text widget ## in each row. ####################################################### for {set k 1} {$k <= $Nsegs} {incr k} { set AR_24HHMMSSstart($k) "" set AR_24HHMMSSend($k) "" eval .fRadseg$k.textSEGlength delete 1.0 end } ## END OF k-loop ###################################################### ## Clear the total, if any, in the TOTAL text widget. ###################################################### .fRbuttons.textTOTAL delete 1.0 end ######################################################### ## To help the user start entering start/end times on ## the first ad-segment line, set the radiobutton variable ## value (which holds the segment-number) to one. ######################################################### set VAR_radbutt_segnum 1 } ## END OF proc 'clear_all' ##+##################################################################### ## proc 'total_all_ads' ##+##################################################################### ## PURPOSE: Totals the 'mmm:ss' values in the text widgets ## that hold the ad-segment lengths: ## .fRadseg$k.textSEGlength ## ## CALLED BY: the 'Total-All-Ads' button ##+##################################################################### proc total_all_ads {} { global Nsegs ## FOR TESTING: (dummy out this proc) # return ######################################################## ## Add up the 'mmm:ss' values from the up-to-Nsegs ## text widgets that hold the ad-segment lengths: ## .fRadseg$k.textSEGlength ## ## We add the 'mmm' and 'ss' values separately, and ## later deal with the 'ss' total if it goes over 59. ####################################################### set TOTmmm 0 set TOTss 0 for {set k 1} {$k <= $Nsegs} {incr k} { set tempSEGLEN [.fRadseg$k.textSEGlength get 1.0 end] set tempSEGLEN [string trim "$tempSEGLEN"] if {"$tempSEGLEN" != ""} { set SEGLENlist [split "$tempSEGLEN" :] set tempMMM [lindex $SEGLENlist 0] set tempSS [lindex $SEGLENlist 1] ########################################################## ## If there are leading zeros on tempSS, remove ## them to avoid 'invalid octal number as operand' errors ## from '08' and '09'. Ref: http://wiki.tcl.tk/15158 ########################################################## set tempSS [scan $tempSS %d] ## FOR TESTING: if {0} { puts "" puts "tempSEGLEN: $tempSEGLEN" puts "SEGLENlist: $SEGLENlist" puts "tempMMM: $tempMMM" puts "tempSS: $tempSS" } set TOTmmm [expr {$TOTmmm + $tempMMM}] set TOTss [expr {$TOTss + $tempSS}] } ## END OF if {"$tempSEGLEN" != ""} } ## END OF k-loop ################################################# ## If TOTss > 59, convert the excess to minutes ## and add the minutes to TOTmmm. ################################################# if {$TOTss > 59} { set tempMIN [expr {int($TOTss/60.0)}] set TOTss [expr {$TOTss - (60 * $tempMIN)}] set TOTmmm [expr {$TOTmmm + $tempMIN}] } ################################################# ## Put 'TOTmmm:TOTss' in the TOTAL text widget. ################################################# .fRbuttons.textTOTAL delete 1.0 end .fRbuttons.textTOTAL insert 1.0 "${TOTmmm}:[format "%02d" $TOTss]" } ## END OF proc 'total_all_ads' ##+##################################################################### ## proc 'Report' ##+##################################################################### ## PURPOSE: Forms a 'detailed' report consisting of: ## - start & end time hh:mm:ss data for all the ad-segments entered ## - the mmm:ss time lengths from the text widgets ## (.fRadseg$k.textSEGlength) ## - the total ad time (sum of the mmm:ss lengths). ## ## CALLED BY: the 'Report' button ##+##################################################################### proc Report {} { global Nsegs AR_24HHMMSSstart AR_24HHMMSSend ## FOR TESTING: (dummy out this proc) # return ################################# ## Get the date in a nice format. ################################# set DATEstring [clock format [clock seconds] \ -format "%Y %b %d %a %H:%M:%S %Z"] ##################################### ## Prepare the header of the report. ##################################### set REPORTtext "Ad-Time Report $DATEstring showing ad start-time and end-time details and a grand-total-time in 'mins:secs' format. The following start and end times are shown in 'hh:mm:ss' format, in 24-hour time format. Ad Segment Number START-time END-time LENGTH (mmm:ss) ------ ----------- ---------- -------------- " ##################################################### ## Prepare the up-to-Nsegs detail lines of the report, ## while collecting mins,secs totals for the grand total. ##################################################### set TOTmmm 0 set TOTss 0 for {set k 1} {$k <= $Nsegs} {incr k} { set tempSEGLEN [.fRadseg$k.textSEGlength get 1.0 end] set tempSEGLEN [string trim "$tempSEGLEN"] if {"$tempSEGLEN" != ""} { set SEGLENlist [split "$tempSEGLEN" :] set tempMMM [lindex $SEGLENlist 0] set tempSS [lindex $SEGLENlist 1] set tempSS [scan $tempSS %d] set TOTmmm [expr {$TOTmmm + $tempMMM}] set TOTss [expr {$TOTss + $tempSS}] set REPORTtext "$REPORTtext [format "%6s" $k] [format "%10s" $AR_24HHMMSSstart($k)] \ [format "%10s" $AR_24HHMMSSend($k)] [format "%6s" $tempSEGLEN]" } ## END OF if {"$tempSEGLEN" != ""} } ## END OF k-loop ################################################# ## If TOTss > 59, convert the excess to minutes ## and add the minutes to TOTmmm. ################################################# if {$TOTss > 59} { set tempMIN [expr {int($TOTss/60)}] set TOTss [expr {$TOTss - (60 * $tempMIN)}] set TOTmmm [expr {$TOTmmm + $tempMIN}] } ##################################### ## Prepare the trailer of the report. ##################################### set REPORTtext "$REPORTtext TOTAL Ad Time : ${TOTmmm}:[format "%02d" $TOTss] (mins:secs) This report was prepared by the 'tkAdsAdder' Tk GUI script." ##################################### ## Show the report in a popup window. ##################################### popup_msgVarWithScroll .topReport "$REPORTtext" } ## END OF proc 'Report' ##+######################################################################## ## 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 use this 'toplevel-text' method, ## rather than the 'tk_dialog' method -- like 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 } { ## global fontTEMP_varwidth #; Not needed. 'wish' makes this 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 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_fixedwidth \ -width $VARwidth \ -height $VARheight \ -bg "#f0f0f0" \ -relief raised \ -bd 2 \ -yscrollcommand "$toplevName.scrolly set" \ -xscrollcommand "$toplevName.scrollx set" 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_varwidth \ -width $VARwidth \ -height $VARheight \ -bg "#f0f0f0" \ -relief raised \ -bd 2 } 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 } ##################################### ## 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. ##+############################################### ## Setting of HELPtext variable follows. ##+############################################### set HELPtext "\ *** HELP for this 'tkAdsAdder' GUI **** This Tk GUI script provides a GUI for adding up the amount of time spent on commercials (ads) during a TV show. Up to Nsegs commercial segments are accomodated, where Nsegs is about 16, but could be set higher. This is (hopefully) enough segments to handle half-hour and hour shows (such as most situation comedies and crime dramas) --- and even most movies shown on commercial TV. (In 2013, 'commercial segments' in a TV program were typically composed of about 4 to 12 individual ads. The typical 'ads segment' is often split into TWO 'psuedo-segments' by an annuouncer saying something like 'Closed captioning is brought to you by' ... after about 6 ads are presented. Then another 4 to 6 ads are presented. Who do they think they are kidding? Since no real program content is presented during those 10 to 12 ads, the start and end time of the entire set of about a dozen ads should be entered --- i.e. treat the entire mess as one 'segment'.) ****************************** METHOD OF OPERATION OF THE GUI: Two entry fields are provided for each 'segment of commercials' --- to enter a start-time and end-time for each 'segment' of ads. Three 'scale' widgets are at the top of the GUI --- to set an hour, minute, and second --- for the the start and end times of an ad segment. The 3 'scale' widgets are intended to make the entry of time (in the format hh:mm:ss), in each of the entry fields, easy for the keyboard-challenged user. The 'start' or 'end' hours, minutes, and seconds can be entered quickly by dragging the slider button of each of the 3 slider bars. Three radiobuttons, above the 3 'scale' widgets, are to be used to indicate whether the user wants to specify the start/end time as AM or PM or 24-hour time, via the scale widgets. A radiobutton is provided in front of each pair of start/end 'entry' widgets --- to indicate which ad-segment is being specified. After clicking on one of the ad-segment radiobuttons, clicking on the 'EnterStartTime' or 'EnterEndTime' button then determines whether the 3 'scale' widget settings are put into the start or the end entry field for the user-specified ad-segment. Whenever a start-time or an end-time is entered or changed --- and if a start-time and end-time are both non-empty on an 'ad-segment line' --- a calculation is performed to give the length of the ad-segment in the form mins:secs --- shown on the right-side of the 'current-ad-segment' line. ------------------------- GETTING THE 'GRAND-TOTAL': ------------------------- After all the pairs of entry fields for a TV program are entered, the user can click on the 'Total-All-Ads' button, and calculations are performed to provide the total time consumed by all of the ads. When the 'Total-All-Ads' button is clicked, the 'mmm:ss' time-lengths are added up to give the total time of the ads over the entire time that the program ad-times were recorded. The total time (in mmm:ss format) is displayed in a small, one-line text widget on the GUI, next to the 'Total-All-Ads' button. The user can copy-and-paste that time from this GUI to another GUI, such as a text editor GUI. A 'Report' button allows the user to generate a 'detailed' text report that includes all the start and end times and the differences (ad-segment lengths) that went into the total figure. The report is shown in a popup scrollable Tk text widget, from which the user may copy and paste the entire text into another window, such as a text editor or HTML editor or word-processor window. ****************************** TYPICAL SEQUENCE OF OPERATIONS: 1) Set a radiobutton on the left of the 'ad-segment line' in which you want to make a start-time or end-time entry. 2) Check the AM/PM/24 radiobuttons at the top of the GUI to see if they are set according to the way you want to enter the time. 3) Set the hour, minute, second sliders to the time that you want to enter. 4) Click on the 'EnterStartTime' or 'EnterEndTime' button to transfer the time setting from the 3 scale widgets to an entry field on the 'ad-segment line' that you have selected. 5) Continue using steps 1 through 4 to enter start and end times for the ad segments in a TV program. 6) When finished entering start and end times, click on the 'Total-All-Ads' button to show a total time, beside the 'Total-All-Ads' button. Use the 'Report' button for a more detailed report. *************************** FINE CONTROL OF THE SLIDERS: Most people know that you can drag the sliders by clicking on the 'slider button' with mouse-button1 and dragging the slider button. This is a rather coarse way of moving the slider button. It is not so obvious that the Tk scale widget also allows you to move the 'slider button' by clicking in the 'trough' on EITHER SIDE of the slider button. By repeated clicking in the trough, the slider can be advanced one scale-resolution unit per click. Furthermore, one can RAPIDLY move the slider button ONE RESOLUTION UNIT per 'auto-click' by clicking in the trough and HOLDING down the mouse button. The slider moves one resolution unit repeatedly UNTIL the mouse button is RELEASED. ************************* SETUP of this utility: Note that the user can set up this script as an icon on a computing-device 'desktop' so that the GUI can be started up by a click (or two) on the icon --- say, while the user is watching a ad-filled TV program. For example, put the Tk script into a sub-directory of a user's home directory, such as \$HOME/apps/tkAdAdder. " ##+############################################### ## ADDITONAL GUI INITIALIZATION (if any) FOLLOWS. ##+############################################### ## none for now ##+###############################################