Fixed some bugs w.r.t. resizing the window (bars and resources were
[dyninst.git] / visiClients / barchart / tcl / barChart.tcl
1 #
2 #  barChart -- A bar chart display visualization for Paradyn
3 #
4 #  $Log: barChart.tcl,v $
5 #  Revision 1.5  1994/10/07 22:06:36  tamches
6 #  Fixed some bugs w.r.t. resizing the window (bars and resources were
7 #  sometimes redrawn at the old locations, instead of adapting to the
8 #  resize).  The problem was related to [winfo width ...] returning
9 #  the old value while in the middle of a resize event.  The solution
10 #  was to include %w and %h in the configure-even callback (see the
11 #  tk "bind" command man page)
12 #
13 # Revision 1.4  1994/10/04  22:10:56  tamches
14 # more color fixing (moved codes from barChart.C to here)
15 #
16 # Revision 1.3  1994/10/04  19:00:23  tamches
17 # implemented resourceWidth algorithm: try to make resources the maximum
18 # pixel width, but if they don't all fit in the window, shrink (down
19 # to a fixed minimum).  Reapply algorithm when: window resizes, resources
20 # are added/deleted.
21 #
22 # Revision 1.2  1994/10/01  02:22:25  tamches
23 # Fixed some bugs related to scrolling; now, the user can't accidentally
24 # scroll to the left of the leftmost bar or to the right of the rightmost
25 # bar.
26 #
27 # Revision 1.1  1994/09/29  19:49:50  tamches
28 # rewritten for new version of barchart; the bars are now drawn
29 # with xlib code in C++ (no more blt_barchart) in barChart.C.
30 # See also barChartTcl.C and barChartDriver.C
31 #
32 # Revision 1.5  1994/09/08  00:10:43  tamches
33 # Added preliminary blt_drag&drop interface.
34 # changed window title.
35 #
36 # Revision 1.4  1994/09/04  23:55:29  tamches
37 # added 'to do' and 'problems' lists.  tightened code around speed-critical
38 # areas.  improved look of x axis.
39 #
40 # Revision 1.3  1994/09/03  01:24:40  tamches
41 # Cleaned up syntax some more, e.g. longer variable names.
42 # Cleaned up menus
43 # Added many comments
44 #
45 # Revision 1.2  1994/09/02  21:00:30  tamches
46 # minor get-acquainted formatting cleanups
47 #
48 # Revision 1.1  1994/08/06  22:50:47  rbi
49 # Bar Chart Visi originally written by Sherri Frizell.
50 # Initial revision includes bug fixes and cleanups by rbi.
51 #
52
53 # ######################################################
54 # TO DO LIST:
55 # 1) draw numerical values on the bars (menu option) (default=on?)
56 # 2) resources: make deletion work
57 # 3) staggered x-axis names
58 # 4) multiple metrics: put a "key" on screen
59 # 5) multiple metrics: make them show on y axis
60 # 6) multiple metrics: allow deletion
61 # 7) option to sort resources (will be difficult--would need to map resourceid
62 #    as given by visi to our new ordering)
63 # ######################################################
64
65 #  ################### Default options #################
66
67 option add *Visi*font *-New*Century*Schoolbook-Bold-R-*-18-*
68 option add *Data*font *-Helvetica-*-r-*-12-*
69 option add *MyMenu*font *-New*Century*Schoolbook-Bold-R-*-14-*
70
71 if {[string match [tk colormodel .] color] == 1} {
72    # You have a color monitor...
73    # change primary background color from 'bisque' to 'grey'
74    . config -bg grey
75    option add *Background grey
76    option add *activeBackground LightGrey
77    option add *activeForeground black
78    option add *Scale.activeForeground grey
79 } else {
80    # You don't have a color monitor...
81    option add *Background white
82    option add *Foreground black
83 }
84
85 # ####################  Overall frame ###########################
86
87 set yAxisWidth 0.75i
88 set xAxisHeight 0.65i
89
90 set W .bargrph
91 frame $W -class Visi
92
93 frame $W.top
94 pack $W.top -side top -fill x -expand false -anchor n
95    # this area will encompass the title bar, menu bar, and logo
96    # expand is set to false; if the window is made taller,
97    # we don't want to get any taller.
98
99 frame $W.top.left
100 pack $W.top.left -side left -fill both -expand true
101    # this area encompasses the title bar and menu bar
102    # expand is set to true so that if the window is made
103    # wider, we get the extra space (as opposed to the logo
104    # or as opposed to nobody, which would leave ugly blank
105    # space)
106
107 # #################### Paradyn logo #################
108
109 label $W.top.logo -relief raised \
110                   -bitmap @/p/paradyn/core/paradyn/tcl/logo.xbm \
111                   -foreground #b3331e1b53c7
112
113 pack $W.top.logo -side right -expand false
114    # we set expand to false; if the window is made wider, we
115    # don't want any of the extra space; let the menu bar and
116    # title bar have it.
117
118 # #################### Title bar #################
119
120 label $W.top.left.titlebar  -text "BarChart Visualization" -foreground white -background lightslategray
121 pack $W.top.left.titlebar -side top -fill both -expand true
122    # expand is set to true, not because we want more space if the window
123    # is made taller (which won't happen, since the expand flag of our
124    # parent was set to false), but because we want to take up any padding
125    # space left after we and the menu bar are placed (if the logo is
126    # taller than the two of us, which it currently is)
127
128 # ##################### Menu bar ###################
129
130 set Wmbar $W.top.left.mbar
131 frame $Wmbar -class MyMenu -borderwidth 2 -relief raised
132 pack  $Wmbar -side top -fill both -expand false
133
134 # #################### File menu #################
135
136 menubutton $Wmbar.file -text File -menu $Wmbar.file.m
137 menu $Wmbar.file.m
138 $Wmbar.file.m add command -label "Close Bar chart" -command exit
139
140 # #################### Metrics menu ###################
141
142 menubutton $Wmbar.metrics -text Metrics -menu $Wmbar.metrics.m
143 menu $Wmbar.metrics.m
144 $Wmbar.metrics.m add command -label "Add Metric..." -command AddMetricDialog
145 $Wmbar.metrics.m add command -label "Remove Selected Metric" -state disabled
146
147 # #################### Resources menu #################
148
149 menubutton $Wmbar.resources -text Resources -menu $Wmbar.resources.m
150 menu $Wmbar.resources.m
151 $Wmbar.resources.m add command -label "Add Resource..." -command AddResourceDialog
152 $Wmbar.resources.m add command -label "Remove Selected Resource" -state disabled
153 $Wmbar.resources.m add separator
154 $Wmbar.resources.m add radio -label "Order by Name (ascending)" -variable SortPrefs -command ProcessNewSortPrefs -value ByName
155 $Wmbar.resources.m add radio -label "Order by Name (descending)" -variable SortPrefs -command ProcessNewSortPrefs -value ByNameDescending
156 $Wmbar.resources.m add radio -label "Order as Inserted by User" -variable SortPrefs -command ProcessNewSortPrefs -value NoParticular
157
158 # #################### Display menu #################
159
160 menubutton $Wmbar.opts -text "Display" -menu $Wmbar.opts.m
161 menu $Wmbar.opts.m
162 $Wmbar.opts.m add radio -label "Current Value" \
163    -variable DataFormat -command {rethinkDataFormat} \
164    -value Instantaneous
165 $Wmbar.opts.m add radio -label "Average Value" \
166    -variable DataFormat -command {rethinkDataFormat} \
167    -value Average
168 $Wmbar.opts.m add radio -label "Total Value" \
169    -variable DataFormat -command {rethinkDataFormat} \
170    -value Sum
171
172 # #################### Help menu #################
173
174 menubutton $Wmbar.help -text Help \
175           -menu $Wmbar.help.m
176 menu $Wmbar.help.m 
177 $Wmbar.help.m add command -label "General" -command "NotImpl" -state disabled
178 $Wmbar.help.m add command -label "Context" -command "NotImpl" -state disabled
179
180
181 # #################### Build the menu bar and add to display #################
182
183 pack $Wmbar.file $Wmbar.metrics \
184      $Wmbar.resources $Wmbar.opts \
185      -side left -padx 4
186 pack $Wmbar.help -side right
187
188 # #################### Organize all menu buttons into a menubar #################
189
190 tk_menuBar $Wmbar $Wmbar.file $Wmbar.metrics \
191    $Wmbar.resources $Wmbar.opts $Wmbar.help
192
193 # ####################  Barchart Title ("Metric: xxxxxxxx") #################
194
195 label $W.titleLabel -text "(no barchart currently loaded)" \
196                     -font "-adobe-helvetica-bold-o-*-*-*-*-*-*-*-*-iso8859-1"
197 pack  $W.titleLabel -side top -fill x -expand false
198    # expand is set to false; if the window is made taller, we don't want
199    # any of the extra space to go to the title (we want it to go to the
200    # bar graph main area in the middle)
201
202
203 # ####################  Barchart X Axis Title ("Resource(s)") ###############
204
205 label $W.xAxisTitle -text "Resource(s)" \
206                     -font "-adobe-helvetica-bold-o-*-*-*-*-*-*-*-*-iso8859-1"
207 pack  $W.xAxisTitle -side bottom -fill x -expand false
208    # expand is set to false; if the window is made taller, we don't want
209    # extra height to go to us.
210
211 # ###############  A sub-window to hold x-axis scrollbar & some padding ##########
212
213 canvas $W.sbRegion -height 16
214    # on configure events, must update the -scrollregion
215 pack $W.sbRegion -side bottom -expand false -fill x
216    # expand is set to false; if the window is made taller, we don't want
217    # any of the extra height; let the middle section have it.
218
219 canvas $W.sbRegion.padding -width $yAxisWidth -height 16
220 pack $W.sbRegion.padding -side left -expand false
221    # expand is set to false; if the window is made wider, we don't
222    # want any of the extra width.
223
224 scrollbar $W.sbRegion.xAxisScrollbar -orient horizontal -width 16 -foreground gray \
225                             -activeforeground gray -relief sunken \
226                             -command processNewScrollPosition
227 pack $W.sbRegion.xAxisScrollbar -side right -fill x -expand true
228    # expand is set to true; if the window is made wider, we want
229    # extra width.
230
231 # #############  A sub-window to hold x-axis canvas & some padding #########
232
233 canvas $W.bottom -height $xAxisHeight
234 pack   $W.bottom -side bottom -expand false -fill x
235    # expand is set to false; if the window is made taller, we don't want
236    # any of the extra height; let the middle section have it.
237
238 canvas $W.bottom.padding -width $yAxisWidth -height $xAxisHeight
239 pack   $W.bottom.padding -side left -expand false
240    # expand is set to false; if the window is made wider, we don't
241    # want any of the extra width.
242    # We are the blank space at (0,0); we exist to keep the X and Y
243    # axis from getting any of this area, which would be difficult to manage.
244
245 set Wxcanvas $W.bottom.xAxisCanvas
246 canvas $Wxcanvas -height $xAxisHeight -relief groove \
247                              -xscrollcommand myXScroll \
248                              -scrollincrement 1
249 pack   $Wxcanvas -side right -expand true -fill x
250    # expand is set to true; if the window is made wider, we want
251    # extra width.
252
253 # ####################  Y Axis Canvas ##################################
254
255 canvas $W.yAxisCanvas -width $yAxisWidth
256 pack   $W.yAxisCanvas -side left -fill y -expand false
257    # expand is set to false; if the window is made wider, we don't want
258    # extra width to go to the y axis
259
260 # ####################  Barchart Area ($W.body) #################
261
262 canvas $W.body -height 3i -width 2.5i -relief groove
263 #frame $W.body -height 3i -width 2.5i -relief groove
264 pack  $W.body -side top -fill both -expand true
265    # expand is set to true; if the window is made taller, we want the
266    # extra height to go to us (and our slave window $W.body.barCanvas)
267
268 # ####################  Bar Canvas ##############################
269
270 #frame  $W.body.barCanvas -relief groove -background red
271 #pack   $W.body.barCanvas -side top -fill both -expand true
272
273 #canvas $W.body.barCanvas -relief groove
274 #pack   $W.body.barCanvas -side top -fill both -expand true
275
276 # ######### pack $W (and all its subwindows) into the main (top-level) window such that
277 # ######### it basically consumes the entire window...
278 pack append . $W {fill expand frame center}
279
280 # set some window manager hints:
281 wm minsize  . 350 250
282 wm title    . "Barchart"
283
284 proc getWindowWidth {wName} {
285    # warning!  This routine will return an old number if an important
286    # event (i.e. resize) happened but idle routines haven't yet kicked in.
287    # --> *** In such cases, be sure to grab the latest information directly
288    #         from the event structure instead of calling this routine!!!!
289
290    set result [winfo width $wName]
291    if {$result == 1} {
292       set result [winfo reqwidth $wName]
293    }
294
295    return $result
296 }
297
298 proc getWindowHeight {wName} {
299    # warning!  This routine will return an old number if an important
300    # event (i.e. resize) happened but idle routines haven't yet kicked in.
301    # --> *** In such cases, be sure to grab the latest information directly
302    #         from the event structure instead of calling this routine!!!!
303
304    set result [winfo height $wName]
305    if {$result == 1} {
306       set result [winfo reqwidth $wName]
307    }
308
309    return $result
310 }
311
312 # ################ Initialization and LaunchBarChart ######################
313 proc Initialize {} {
314    # a subset of DgConfigCallback that sets important global vrbles
315    # stuff that needs to be in order **BEFORE** the call to launchBarChart
316    # (i.e. launchBarChart depends on these settings)
317
318    # puts stderr "Welcome to Initialize!"
319    # flush stderr
320
321    global W
322    global numMetrics
323    global metricNames
324    global metricUnits
325    global metricMinValues
326    global metricMaxValues
327
328    global numResources
329    global resourceNames
330
331    global currResourceWidth
332    global minResourceWidth
333    global maxResourceWidth
334
335    global DataFormat
336
337    global clickedOnResource
338    global clickedOnResourceText
339    global numLabelsDrawn
340    global numResourcesDrawn
341
342    global SortPrefs
343    global barColors
344    global numBarColors
345
346    set SortPrefs NoParticular
347    
348    set clickedOnResource ""
349    set clickedOnResourceText ""
350    set numLabelsDrawn 0
351    set numResourcesDrawn 0
352
353    set DataFormat Instantaneous
354    set numMetrics [Dg nummetrics]
355
356    for {set metriclcv 0} {$metriclcv < $numMetrics} {incr metriclcv} {
357       set metricNames($metriclcv) [Dg metricname  $metriclcv]
358       set metricUnits($metriclcv) [Dg metricunits $metriclcv]
359       set metricMinValues($metriclcv) [lindex [getMetricHints $metricNames($metriclcv)] 1]
360       set metricMaxValues($metriclcv) [lindex [getMetricHints $metricNames($metriclcv)] 2]
361    }
362
363    set numResources [Dg numresources]
364    for {set resourcelcv 0} {$resourcelcv < $numResources} {incr resourcelcv} {
365       set resourceNames($resourcelcv) [Dg resourcename $resourcelcv]
366    }
367
368    set minResourceWidth 45
369    set maxResourceWidth 90
370    set currResourceWidth $maxResourceWidth
371       # as resources are added, we try to shrink the resource width down to a minimum of
372       # (minResourceWidth) rather than having to invoke the scrollbar.
373       # The question then becomes, if the window is made wider, should we
374       # tend "resourceWidth" back toward "maxResourceWidth", if it had been shrunk
375       # toward "minResourceWidth"?  Or once a resource is shrunk, should it never
376       # be enlarged?
377
378    # bar colors: (see /usr/lib/X11/rgb.txt)
379    # purple is reserved for the where axis.
380    # red should not be next to green; they look equal to colorblind
381    # use greyscales if b&w monitor
382 #   set barColors(0) "tomato"
383    set barColors(0) "cornflower blue"
384    set barColors(1) "medium sea green"
385    set barColors(2) "hotpink"
386    set barColors(3) "chocolate"
387    set barColors(4) "orange"
388    set numBarColors 5
389
390    # launch our C++ barchart code
391    # launchBarChart $W.body.barCanvas doublebuffer noflicker $numMetrics $numResources 0
392    launchBarChart $W.body doublebuffer noflicker $numMetrics $numResources 0
393
394    # trap window resize and window expose events --- for the subwindow
395    # containing the bars only, however.  Note that using
396    # $W.body instead of "." avoids LOTS of unneeded
397    # configuration callbacks.  In particular, when a window is just
398    # moved, it won't create a callback (yea!)  This means we
399    # can treat a configuration event as a true resize.
400
401    # [sec 19.2: 'event patterns' in tk/tcl manual]
402
403    bind $W.body <Configure> {myConfigureEventHandler %w %h}
404    bind $W.body <Expose>    {myExposeEventHandler}
405 }
406
407 # ############################################################################
408 # ####################### important procedures ###############################
409 # ############################################################################
410 #
411 # LOW-LEVEL PROCEDURES:
412 # processEnterResource - given a widget name, let the user know that clicking
413 #                        on it will enable the "delete" item under the resource
414 #                        menu. Called when the mouse enters the widget.
415 # processClickResource - Bound to buttonpress in resource widgets; just
416 #                        calls selectResource
417 # processExitResource - Bound to when the mouse leaves a resource message widget.
418 #                       depending on whether the user clicked, we do something
419 #                       appropriate user-interface-speaking.
420 #
421 # drawXaxis - Completely rethinks the layout of the x axis and its scrollbar, and
422 #             redraws them.  Call at the beginning of the program, after the window
423 #             is resized, and when resources (or metrics) are added or deleted.
424 #
425 # drawYaxis - analagous to drawXaxis...
426 #
427 # drawTitle - rethinks and redraws the chart title (just below the menubar).
428 #             Call at the beginning of the program and when metrics are
429 #             added or deleted (since they comprise the title)
430 #
431 # myConfigureEventHandler - called whenever the window configuration has changed
432 #
433 # HIGH-LEVEL PROCEDURES:
434 # selectResource - given a widget name, select it and enable the "delete resource"
435 #                  menu item.
436 # unSelectResource - un-select the widget and disable the "delete resource" menu item.
437 # addResource - given a new resource name, adds it (calling drawXaxis, etc.
438 #               automatically).
439 #
440 # delResource - given an index (0 thru numResources-1), deletes it (calling
441 #               drawXaxis, etc. automatically)
442
443 # addMetric - given a new metric name (and its units), adds it (calling drawXaxis,
444 #             drawYaxis, drawTitle, etc. automatically)
445 #
446 # delMetric - analagous to delResource...
447 #
448 # ############################################################################
449
450 proc selectResource {widgetName} {
451    global clickedOnResource
452    global clickedOnResourceText
453    global Wmbar
454
455    # if someone else was previous selected, un-select him
456    if {$clickedOnResource != ""} {
457       unSelectResource $clickedOnResource
458    }
459
460    # select
461    set clickedOnResource $widgetName
462    set clickedOnResourceText [lindex [$widgetName configure -text] 4]
463    $widgetName configure -relief sunken
464    $Wmbar.resources.m entryconfigure 1 -state normal \
465            -label "Remove \"$clickedOnResourceText\"" \
466            -command {delResourceByName $clickedOnResourceText}
467 }
468
469 proc unSelectResource {widgetName} {
470    global clickedOnResource
471    global clickedOnResourceText
472    global Wmbar
473
474    set clickedOnResource ""
475    set clickedOnResourceText ""
476    $widgetName configure -relief flat
477    $Wmbar.resources.m entryconfigure 1 -state disabled \
478            -label "Remove Selected Resource" \
479            -command {puts "ignoring unexpected deletion..."}
480 }
481
482 proc processEnterResource {widgetName} {
483    global clickedOnResource
484    global clickedOnResourceText
485
486    # if this widget has already been clicked on, do nothing
487    if {$widgetName == $clickedOnResource} {
488       return
489    }
490
491    $widgetName configure -relief groove
492 }
493
494 proc processClickResource {widgetName} {
495    selectResource $widgetName
496 }
497
498 proc processExitResource {widgetName} {
499    global clickedOnResource
500    global clickedOnResourceText
501
502    # if we clicked on this guy, then do nothing (keep him selected),
503    # otherwise undo the -relief groove
504    if {$clickedOnResource != $widgetName} {
505       $widgetName configure -relief flat
506    }
507 }
508
509 proc rethinkResourceWidths {screenWidth} {
510    # When resources are added or deleted, this routine is called.
511    # Its sole purpose is to rethink the value of currResourceWidth,
512    # depending on the resources.
513
514    # algorithm: get current window width.  set resource width equal
515    # to window width / num resources.  If that would make the resource
516    # width too small, make the resource width currResourceWidth
517    global minResourceWidth
518    global maxResourceWidth
519    global currResourceWidth
520    global numResources
521    global Wxcanvas
522
523    set tentativeResourceWidth [expr $screenWidth / $numResources]
524    if {$tentativeResourceWidth < $minResourceWidth} {
525       set tentativeResourceWidth $minResourceWidth
526    } elseif {$tentativeResourceWidth > $maxResourceWidth} {
527       set tentativeResourceWidth $maxResourceWidth
528    }
529
530    set currResourceWidth $tentativeResourceWidth
531
532    # puts stderr "Leaving rethinkResourceWidths; we have decided upon $currResourceWidth"
533 }
534
535 proc drawXaxis {xAxisWidth} {
536    # how it works: deletes all canvas items with the tag "xAxisItemTag", including
537    # the window items.  message widgets have to be deleted separately, notwithstanding
538    # the fact that the canvas window items were deleted already.
539    # (it knows how many message widgets there are via numResourcesDrawn, which at the
540    # time this routine is called, may not be up-to-date with respect to numResources),
541    # and then redraws by re-recreating the canvas items and message widgets
542
543    global W
544    global Wmbar
545    global Wxcanvas
546
547    global xAxisHeight
548    global yAxisWidth
549
550    global numResources
551    global numResourcesDrawn
552    global resourceNames
553    global clickedOnResource
554    global clickedOnResourceText
555
556    global minResourceWidth
557    global maxResourceWidth
558    global currResourceWidth
559
560    global SortPrefs
561
562    # puts stderr "Welcome to drawXaxis"
563    # flush stderr
564
565    set top 3
566    set tickHeight 5
567    set resourceNameFont -adobe-courier-medium-r-normal-*-12-120-*-*-*-*-iso8859-1
568
569    # ###### delete leftover stuff
570    $Wxcanvas delete xAxisItemTag
571    for {set rindex 0} {$rindex < $numResourcesDrawn} {incr rindex} {
572       destroy $Wxcanvas.message$rindex
573    }
574
575    # next, several tick marks extending down a few pixels from the x axis (one per resource),
576    # plus (while we're at it) the text of the given resources (centered at their respective
577    # tick marks)
578
579    # yet to implement: STAGGERED TEXT
580    #         needed  : a way to detect when two message widgets have collided.
581    #                   doesn't sound too difficult... (use winfo -geometry for each widget)
582
583    set right 0
584    for {set rindex 0} {$rindex < $numResources} {incr rindex} {
585       set left [expr $rindex * $currResourceWidth]
586       set right [expr $left + $currResourceWidth - 1]
587       set middle [expr ($left + $right) / 2]
588
589       # create a tick line
590       $Wxcanvas create line $middle $top $middle [expr $top+$tickHeight-1] -tag xAxisItemTag
591
592       # create a message widget, bind some commands to it, and attach it to the
593       # canvas via "create window"
594
595       set theText $resourceNames($rindex)
596
597       message $Wxcanvas.message$rindex -text $theText \
598                                            -justify center -width $currResourceWidth \
599                                            -font $resourceNameFont
600       bind $Wxcanvas.message$rindex <Enter> \
601                           {processEnterResource %W}
602       bind $Wxcanvas.message$rindex <Leave> \
603                           {processExitResource %W}
604       bind $Wxcanvas.message$rindex <ButtonPress> \
605                           {processClickResource %W}
606       $Wxcanvas create window $middle [expr $top+$tickHeight] \
607                                          -anchor n -tag xAxisItemTag \
608                                          -window $Wxcanvas.message$rindex
609    }
610
611    # the axis itself--a horizontal line
612    $Wxcanvas create line 0 $top $right $top -tag xAxisItemTag
613
614    # Update the scrollbar's scrollregion configuration:
615    set regionList {0 0 0 0}
616    set regionList [lreplace $regionList 2 2 $right]
617    set regionList [lreplace $regionList 3 3 $xAxisHeight]
618    $Wxcanvas configure -scrollregion $regionList
619
620    set screenWidth $xAxisWidth
621
622    set oldconfig [$W.sbRegion.xAxisScrollbar get]
623    set oldTotalWidth [lindex $oldconfig 0]
624
625    if {$oldTotalWidth != $right} {
626       # puts stderr "drawXaxis: detected major change in resources ($oldTotalWidth != $right), resetting"
627       set firstUnit 0
628    } else {
629       # no change
630       set firstUnit [lindex $oldconfig 2]
631    }
632
633    set lastUnit [expr $firstUnit + $screenWidth - 1]
634    # puts stderr "setting sb: $right $screenWidth $firstUnit $lastUnit"   
635    $W.sbRegion.xAxisScrollbar set $right $screenWidth $firstUnit $lastUnit
636                                   
637    # set the maximum width of the window to be $right + $yAxisWidth
638    # wm maxsize . [expr $right + inches2pixels($yAxisWidth)] [unlimited-y-size]
639
640    set numResourcesDrawn $numResources
641 }
642
643 proc processNewMetricMax {mindex newmaxval} {
644    # called from barChart.C when y-axis overflow is detected and
645    # a new max value is chosen
646    global metricMinValues
647    global metricMaxValues
648    global W
649
650    set metricMaxValues($mindex) $newmaxval
651
652    drawYaxis [getWindowHeight $W.yAxisCanvas]
653 }
654
655 proc drawYaxis {yAxisHeight} {
656    # the y axis changes to reflect the units of the current metric(s).
657    # It is not necessary to call drawYaxis if the window width is
658    # resized; it IS necessary to call drawYaxis if the window
659    # height is changed.
660    # It is not necessary to call drawYaxis if resources are
661    # added or removed; it IS necessary to call drawYaxis if
662    # metrics are added or removed.
663
664    global W
665    global numMetrics
666    global numLabelsDrawn
667    global metricNames
668    global metricUnits
669    global metricUnitTypes
670    global metricMinValues
671    global metricMaxValues
672
673    # puts stderr "welcome to drawYaxis"
674
675    # first, delete all leftover canvas items (those with a yaxis tag to them)
676    $W.yAxisCanvas delete yAxisTag
677
678    # we still have to delete the label widgets, which can't have tags...
679    set numlabels 3
680    for {set labelindex 0} {$labelindex < $numLabelsDrawn} {incr labelindex} {
681       destroy $W.yAxisCanvas.label$labelindex
682    }
683
684    # canvas item: the axis itself (a vertical line)
685    set winHeight $yAxisHeight
686    set winWidth [getWindowWidth $W.yAxisCanvas]
687
688    set tickWidth 5
689    set left 5
690    set right [expr $winWidth - 5]
691    set tickLeft [expr $right-$tickWidth+1]
692    set top   5
693    set bottom [expr $winHeight - 5]
694    set labelRight [expr $tickLeft]
695    set labelWidth [expr $labelRight - $left + 1]
696    set height [expr $bottom - $top + 1]
697    set tickStep [expr ($height-1) / ($numlabels-1)]
698
699    set numericalStep [expr (1.0 * $metricMaxValues(0)-$metricMinValues(0)) / ($numlabels-1)]
700
701    # puts stderr "drawYaxis: numericalStep is $numericalStep; metric-min is $metricMinValues(0); metric-max is $metricMaxValues(0)"
702    # flush stderr
703
704    $W.yAxisCanvas create line $right $top $right $bottom -tag yAxisTag
705
706    set labelFont -adobe-courier-medium-r-normal-*-12-120-*-*-*-*-iso8859-1
707    # draw tick marks, and while we're at it, their associated message widgets
708    for {set labelindex 0} {$labelindex < $numlabels} {incr labelindex} {
709       set currY [expr $bottom - round($labelindex*$tickStep)]
710
711       $W.yAxisCanvas create line $tickLeft $currY $right $currY -tag yAxisTag
712
713       set labelText [expr $metricMinValues(0) + $labelindex*$numericalStep]
714       message $W.yAxisCanvas.label$labelindex -text $labelText \
715               -justify right -width $labelWidth \
716               -font $labelFont
717
718       $W.yAxisCanvas create window $labelRight $currY -anchor e \
719                         -tag yAxisItemTag \
720                         -window $W.yAxisCanvas.label$labelindex
721    }
722
723    set numLabelsDrawn $numlabels
724 }
725
726 proc drawTitle {} {
727    # the title changes to reflect the current metric(s)
728    # currently, only a single metric is supported
729
730    global W
731    global numMetrics
732    global metricNames
733    global metricUnits
734
735    if {$numMetrics == 0} {
736       set newTitle "(no metrics currently defined)"
737    } else {
738       set newTitle "Metric: $metricNames(0) (Units: $metricUnits(0))"
739    }
740
741    $W.titleLabel configure -text $newTitle
742 }
743
744 proc myConfigureEventHandler {newWidth newHeight} {
745    #puts stderr "Welcome to myConfigureEventHandler; newWidth=$newWidth; newHeight=$newHeight"
746    #flush stderr
747
748    # rethink how wide the resources should be
749    rethinkResourceWidths $newWidth
750
751    # Call drawXaxis to rethink the scrollbar and to rethink the resource widths
752    drawXaxis $newWidth
753
754    # We only need to redraw the y axis if the window height has changed
755    # (and at the beginning of the program)
756    drawYaxis $newHeight
757
758    # Redraw the title (only needed if metrics changed)
759    drawTitle
760    
761    # if the x axis has changed then call this: (barChart.C)
762    xAxisHasChanged $newWidth
763
764    # if the y axis has changed then call this: (barChart.C)
765    yAxisHasChanged $newHeight
766
767    # inform our C++ code (barChart.C) that a resize has taken place
768    resizeCallback $newWidth $newHeight
769 }
770
771 proc myExposeEventHandler {} {
772    # puts stderr "barChart.tcl -- welcome to myExposeEventHandler"
773    # flush stderr
774
775    # all tk widgets redraw automatically (though not 'till the next idle)
776
777    # all that's left to do is inform our C++ code of the expose
778    exposeCallback
779 }
780
781 proc addResource {rName} {
782    global numResources
783    global resourceNames
784    global W
785
786    # first, make sure this resource doesn't already exist
787    for {set rindex 0} {$rindex < $numResources} {incr rindex} {
788       if {$resourceNames($rindex) == $rName} {
789          puts stderr "detected a duplicate resource: $rname (ignoring addition request)"
790          return
791       } 
792    }
793
794    set resourceNames($numResources) $rName
795    incr numResources
796
797    drawXaxis [getWindowWidth $W.bottom.xAxisCanvas]
798 }
799
800 proc delResource {delindex} {
801    global numMetrics
802    global numResources
803    global resourceNames
804    global clickedOnResource
805    global clickedOnResourceText
806    global Wmbar
807    global W
808
809    # first, make sure this resource index is valid
810    if {$delindex < 0 || $delindex >= $numResources} {
811       puts stderr "delResource -- ignoring out of bounds index: $delindex"
812       return
813    }
814
815    if {$clickedOnResourceText == $resourceNames($delindex)} {
816       set clickedOnResource ""
817       $Wmbar.resources.m entryconfigure 1 -state disabled \
818               -label "Remove Selected Resource" \
819               -command {puts stderr "ignoring unexpected deletion..."}
820    } else {
821       puts stderr "delResource -- no mbar changes since $clickedOnResourceText != $resourceNames($delindex)"
822    }
823
824    # inform that visi lib that we don't want to receive anything
825    # more about this resource
826    # NOTE: unfortunately, [Dg numResources] etc. will not be
827    #       lowered, even after this is done!  (******A bug********)
828    #       The temporary solution is to rigidly test the
829    #       Valid bit of each metric-resource pair before
830    #       drawing, etc.
831    for {set mindex 0} {$mindex < $numMetrics} {incr mindex} {
832       Dg stop $mindex $delindex
833    }
834    
835    # shift resourceNames
836    for {set rindex $delindex} {$rindex < [expr $numResources - 1]} {incr rindex} {
837       set resourceNames($rindex) $resourceNames([expr $rindex + 1])
838    }
839
840    set numResources [Dg numresources]
841       # as mentioned above, the current visi-lib won't
842       # lower the value by 1...
843
844    # callback to barChart.C
845    xAxisHasChanged
846
847    drawXaxis [getWindowWidth $W.bottom.xAxisCanvas]
848 }
849
850 proc delResourceByName {rName} {
851    global numResources
852    global resourceNames
853
854    # find the appropriate index and call delResource...
855    for {set rindex 0} {$rindex < $numResources} {incr rindex} {
856       if {$rName == $resourceNames($rindex)} {
857          delResource $rindex
858          return
859       }
860    }
861
862    puts stderr "delResourceByName: ignoring request to delete resource named: $rName (no such resource)"
863 }
864
865 proc getMetricHints {theMetric} {
866    # #pragma HACK begin
867    # return metric unit type, hinted min, hinted max, hinted step
868    # depending on the metric (a hardcoded temporary hack)
869    switch $theMetric {
870       "exec_time"        {return {percentage 0.0 1.0 0.1}}
871       "hybrid_cost"      {return {real 0.0 1.0 0.1}}
872       "procedure_calls"  {return {integer 0 1000 100}}
873       "predicted_cost"   {return {real 0.0 1.0 .1}}
874       "msgs"             {return {integer 0 10 10}}
875       "msg_bytes"        {return {integer 0 100 100}}
876       "pause_time"       {return {percentage 0.0 1.0 .1}}
877       "msg_bytes_sent"   {return {integer 0 100 100}}
878       "msg_bytes_recv"   {return {integer 0 100 100}}
879       "active_processes" {return {integer 0 1 1}}
880       "sync_ops"         {return {real 0.0 5 1}}
881       "observed_cost"    {return {real 0.0 1.0 0.1}}
882       "sync_wait"        {return {integer 0.0 5 1}}
883       "active_slots"     {return {integer 0.0 2 1}}
884       "cpu"              {return {real 0.0 1.0 0.1}}
885    }
886
887    puts stderr "NOTICE -- getMetricHints: unexpected metric: $theMetric...continuing"
888    return {real 0.0 1.0 0.1}
889    # #pragma HACK done
890 }
891
892 proc addMetric {theName theUnits} {
893    global numMetrics
894    global metricNames
895    global metricUnits
896    global metricUnitTypes
897    global metricMinValues
898    global metricMaxValues
899    global W
900
901    puts stderr "Welcome to addMetric; name is $theName; units are $theUnits"
902
903    # first make sure that this metric isn't already present (if so, do nothing)
904    for {set metricIndex 0} {$metricIndex < $numMetrics} {incr metricIndex} {
905       if {$metricNames($metricIndex) == $theName} {
906          puts stderr "addMetric: ignoring request to add $theName (already present)"
907          return
908       }
909    }
910
911    # make the addition
912    set metricNames($numMetrics) $theName
913    set metricUnits($numMetrics) $theUnits
914
915    set theHints [getMetricHints $theName]
916
917    set metricUnitTypes($numMetrics) [lindex $theHints 0]
918    set metricMinValues($numMetrics) [lindex $theHints 1]
919    set metricMaxValues($numMetrics) [lindex $theHints 2]
920
921    incr numMetrics
922
923    drawXaxis [getWindowWidth $W.bottom.xAxisCanvas]
924    drawYaxis [getWindowHeight $W.yAxisCanvas]
925    drawTitle
926 }
927
928 proc delMetric {delIndex} {
929    global numMetrics
930    global metricNames
931    global metricUnits
932    global W
933
934    # first, make sure this metric index is valid
935    if {$delIndex < 0 || $delIndex >= $numMetrics} {
936       puts stderr "delMetric: ignoring out of bounds index: $delIndex"
937       return
938    }
939
940    # shift
941    for {set mindex $delIndex} {$mindex < [expr $numMetrics-1]} {incr mindex} {
942       set metricNames($mindex) $metricNames([expr $mindex + 1])
943       set metricUnits($mindex) $metricUnits([expr $mindex + 1])
944    }
945
946    set numMetrics [expr $numMetrics - 1]
947    
948    drawTitle
949    drawXaxis [getWindowWidth $W.bottom.xAxisCanvas]
950    drawYaxis [getWindowHeight $W.yAxisCanvas]
951
952    # don't we need to tell paradyn to stop sending us data on
953    # this metric?
954 }
955
956 proc processNewScrollPosition {newTop} {
957    # the -command configuration of the scrollbar is fixed to call this procedure.
958    # This happens whenever scrolling takes place.  We update the x-axis canvas
959    global Wxcanvas
960    global W
961
962    # puts stderr "barChart.tcl: welcome to processNewScrollPosition: newTop is now: $newTop"
963
964    if {$newTop < 0} {
965       set newTop 0
966    }
967
968    # if max <= visible then set newTop 0
969    set currSettings [$W.sbRegion.xAxisScrollbar get]
970    set totalSize [lindex $currSettings 0]
971    set visibleSize [lindex $currSettings 1]
972
973    if {$visibleSize > $totalSize} {
974       set newTop 0
975    } elseif {[expr $newTop + $visibleSize] > $totalSize} {
976       set newTop [expr $totalSize - $visibleSize]
977    }
978
979    # update the x-axis canvas
980    # will automatically generate a call to myXScroll, which then updates the
981    # look of the scrollbar to reflect the new position...
982    $Wxcanvas xview $newTop
983
984    # call our C++ code to update the bars
985    newScrollPosition $newTop
986 }
987
988 proc myXScroll {totalSize visibleSize left right} {
989    # the -scrollcommand configuration of the x axis canvas.
990    # gets called whenever the canvas view changes or is resized.
991    # The idea is to give us the opportunity to rethink the scrollbar that
992    # we are associated with.  Four parameters are passed: total size,
993    # window size, left, right---arguments which we simply pass to the "set"
994    # command of the scrollbar
995
996    global W
997
998    $W.sbRegion.xAxisScrollbar set $totalSize $visibleSize $left $right
999 }
1000
1001 # ############################################################################
1002 # ############# blt_drag&drop: declare that we are willing and able ##########
1003 # ######### to receive drag n' drops of type "text" (the type may change) ####
1004 # ############################################################################
1005
1006 proc dragAndDropTargetHandler {} {
1007    # according to the drag n' drop interface, this routine will be
1008    # called via a "send" command from the source.  So don't expect
1009    # to see this routine called from elsewhere in this file...
1010
1011    # the variable DragDrop(text) contains what should be added
1012    global DragDrop
1013
1014    # not yet implemented...
1015    puts stderr "Welcome to dragAndDropTargetHandler(); DragDrop(text) is $DragDrop(text)"
1016    addResource $DragDrop(text)
1017 }
1018
1019 #blt_drag&drop target . handler text dragAndDropTargetHandler
1020 #...that cryptic line reads: "declare the window '.' to be a drag n' drop
1021 #   handler for sources of type 'text'; routine dragAndDropTargetHandler
1022 #   gets called (via a "send" from the source...)  Using window '.' means
1023 #   the entire barchart...
1024
1025 # #################### Called by visi library when histos have folded #################
1026
1027 proc DgFoldCallback {} {
1028    puts stderr "FOLD detected..."
1029    flush stderr
1030 }
1031
1032
1033 # ########### Called by visi library when metric/resource space changes. #######
1034 #
1035 # note: this routine is too generic; in the future, we plan to
1036 # implement callbacks that actually tell what was added (as opposed
1037 # to what was already there...)
1038 #
1039 # ###############################################################################
1040
1041 proc DgConfigCallback {} {
1042    # puts stderr "Welcome to DgConfigCallback"
1043    # flush stderr
1044
1045    global W
1046
1047    global numMetrics
1048    global metricNames
1049    global metricUnits
1050    global metricMinValues
1051    global metricMaxValues
1052
1053    global numResources
1054    global numResourcesDrawn
1055    global resourceNames
1056
1057    set numMetrics [Dg nummetrics]
1058    for {set metriclcv 0} {$metriclcv < $numMetrics} {incr metriclcv} {
1059       set metricNames($metriclcv) [Dg metricname  $metriclcv]
1060       set metricUnits($metriclcv) [Dg metricunits $metriclcv]
1061
1062       # note -- the following 2 lines are very dubious for already-existing
1063       #         resources (i.e. we should try to stick with the initial values)
1064       set metricMinValues($metriclcv) [lindex [getMetricHints $metricNames($metriclcv)] 1]
1065       set metricMaxValues($metriclcv) [lindex [getMetricHints $metricNames($metriclcv)] 2]
1066    }
1067
1068    set numResources [Dg numresources]
1069    for {set resourcelcv 0} {$resourcelcv < $numResources} {incr resourcelcv} {
1070       set resourceNames($resourcelcv) [file tail [Dg resourcename $resourcelcv]]
1071    }
1072
1073    # rethink the layout of the axes
1074    rethinkResourceWidths [getWindowWidth $W.bottom.xAxisCanvas]
1075    drawXaxis [getWindowWidth $W.bottom.xAxisCanvas]
1076    drawYaxis [getWindowHeight $W.yAxisCanvas]
1077    drawTitle
1078
1079    # inform our C++ code that stuff has changed
1080    xAxisHasChanged [getWindowWidth $W.bottom.xAxisCanvas]
1081    yAxisHasChanged [getWindowHeight $W.yAxisCanvas]
1082 }
1083
1084 # #################  AddMetricDialog -- Ask paradyn for another metric #################
1085
1086 proc AddMetricDialog {} {
1087    Dg start "*" "*"
1088 }
1089
1090 # #################  AddResourceDialog -- Ask paradyn for another resource #################
1091
1092 proc AddResourceDialog {} {
1093    Dg start "*" "*"
1094 }
1095
1096 proc ProcessNewSortPrefs {} {
1097    global SortPrefs
1098
1099    # redraw the x axis
1100    drawXaxis
1101
1102    # redraw the bars (callback to our C++ code)
1103    xAxisHasChanged
1104 }
1105
1106 proc rethinkDataFormat {} {
1107    # invoked when a menu item from among "current, average, total"
1108    # is selected
1109    global W
1110    global DataFormat
1111    global numMetrics
1112    global metricMinValues
1113    global metricMaxValues
1114    global metricNames
1115
1116    # reset y-axis min & max values
1117    for {set metriclcv 0} {$metriclcv < $numMetrics} {incr metriclcv} {
1118       set metricMinValues($metriclcv) [lindex [getMetricHints $metricNames($metriclcv)] 1]
1119       set metricMaxValues($metriclcv) [lindex [getMetricHints $metricNames($metriclcv)] 2]
1120    }
1121
1122    # inform our C++ code that the data format has changed
1123    dataFormatHasChanged
1124
1125    # redraw the y axis
1126    drawYaxis [getWindowHeight $W.yAxisCanvas]
1127 }
1128
1129 # ######################################################################################
1130 #                           "Main Program"
1131 # ######################################################################################
1132
1133 Initialize