minor cvs fixes
[dyninst.git] / visiClients / barchart / barChart.C
1 // This is the C++ portion of barchart version 2.
2 // Much of the user interface mundane stuff (menus, etc.) is still
3 // programmed in tk/tcl in barChart.tcl.
4
5 /* $Log: barChart.C,v $
6 /* Revision 1.2  1994/09/29 20:05:32  tamches
7 /* minor cvs fixes
8 /*
9  * Revision 1.1  1994/09/29  19:48:27  tamches
10  * initial implementation.  A to-do list is kept in barChart.tcl
11  *
12  */
13
14 // tk/tcl has a very nice interface for mixing C++ and tk/tcl
15 // scripts.  From within tcl, C++ code can be called via
16 // new commands; new commands are created with a call
17 // to Tcl_CreateCommand(...)  Unfortunately, you can see
18 // a catch-22 here; in order to even call Tcl_CreateCommand(),
19 // we need to be out of tcl and in C++!  The only way around
20 // this problem is to start the process in C++ and have it
21 // call tk/tcl.  This is done with Tcl_EvalFile(...).  Of
22 // course, just before this, we sneak in our Tcl_CreateCommand()
23 // call.
24
25 // Somewhere in the tk library, there is a main() that
26 // basically does this for us; you have to provide a -f tcl-file-name
27 // option so it knows what to send to Tcl_EvalFile(...)
28 // This main() assumes a function Tcl_InitApp(), which will
29 // be called before the Tcl_EvalFile() is performed...that's
30 // the time to sneak in our Tcl_CreateCommand() stuff...
31
32 #include <assert.h>
33 #include <stdlib.h> // exit()
34 #include <iostream.h>
35 #include <math.h>
36
37 #include <tcl.h>
38 #include <tk.h>
39
40 #include "visi/h/visualization.h"
41 #include "dg2.h"
42 #include "barChartTcl.h"
43
44 #pragma implementation "array2d.h"
45
46 #include "barChart.h"
47
48 BarChart *theBarChart; // main data structure; holds bar information.  Does not
49                        // hold x axis or y axis information (or contents), because
50                        // they are managed just fine from tcl (barChart.tcl) at present.
51                        // Created dynamically in DrawBarsInstallCommand.  Cannot be
52                        // created before then since necessary constructor arguments
53                        // such as tk window name are not yet known.
54
55 /* ********************************************************************
56  * *********************** BarChart methods ***************************
57  * ********************************************************************
58 */
59
60 BarChart::BarChart(char *tkWindowName,
61                    const bool dblBuffer, const bool noFlicker,
62                    const int initNumMetrics, const int initNumResources,
63                    const bool initFlushFlag) :
64             metricColors(initNumMetrics),
65             prevBarHeights(initNumMetrics, initNumResources),
66             barXoffsets(initNumMetrics, initNumResources),
67             barWidths  (initNumMetrics, initNumResources),
68             barHeights (initNumMetrics, initNumResources),
69             barValues  (initNumMetrics, initNumResources),
70             metricCurrMaxYs(initNumMetrics),
71             flushFlag (initFlushFlag)
72              {
73
74    theWindowName = new char[strlen(tkWindowName)+1];
75    if (theWindowName == NULL)
76       panic("BarChart constructor: out of memory!");
77    strcpy(theWindowName, tkWindowName);
78
79    theWindow = Tk_NameToWindow(MainInterp, tkWindowName, Tk_MainWindow(MainInterp));
80    if (theWindow == NULL)
81       panic("BarChart constructor: Tk_NameToWindow() failed!");
82
83    HaveSeenFirstGoodWid = false;
84    wid      = Tk_WindowId(theWindow);
85    borderPix = 2;
86    currScrollOffset = 0;
87    width    = Tk_Width(theWindow);
88    height   = Tk_Height(theWindow);
89    isMapped = Tk_IsMapped(theWindow);
90    display  = Tk_Display(theWindow);
91    width  -= borderPix*2;
92    height -= borderPix*2;
93    
94    greyColor = Tk_GetColor(MainInterp, theWindow, None, Tk_GetUid("grey"));
95
96    DataFormat = Current;
97    
98    drawMode = dblBuffer ? DoubleBuffer : (noFlicker ? NoFlicker : Flicker);
99
100    RethinkMetricsAndResources();
101       // sets numMetrics, numResources, barXoffets, barWidths,
102       // barHeights, prevBarHeights, barValues, metricCurrMaxYs
103 }
104
105 BarChart::~BarChart() {
106    Tk_CancelIdleCall(lowestLevelDrawBars, NULL);
107
108    delete [] theWindowName;
109
110    XFreeGC(display, myGC);   
111
112    Tk_FreeColor(greyColor);
113    for (int metriclcv=0; metriclcv<numMetrics; metriclcv++)
114       Tk_FreeColor(metricColors[metriclcv]);
115
116    changeDoubleBuffering(false, false); // free offscreen pixmap, if necessary
117 }
118
119 void BarChart::changeDoubleBuffering(bool doubleBuffer, bool noFlicker) {
120    // note that we don't try to optimize and return immediately if
121    // the mode hasn't changed.  Why? to accomodate possible change in size.
122
123    if (!HaveSeenFirstGoodWid)
124       return;
125
126    DrawModes newDrawMode;
127    if (doubleBuffer)
128       newDrawMode = DoubleBuffer;
129    else if (noFlicker)
130       newDrawMode = NoFlicker;
131    else
132       newDrawMode = Flicker;
133
134    if (drawMode == DoubleBuffer)
135       // erase offscreen pixmap and reallocate with new size
136       XFreePixmap(display, doubleBufferPixmap);
137
138    drawMode = newDrawMode;
139
140    if (drawMode == DoubleBuffer)
141       doubleBufferPixmap = XCreatePixmap(display, wid,
142                                          Tk_Width(theWindow),
143                                          Tk_Height(theWindow),
144                                          Tk_Depth(theWindow));
145          // note that we use Tk_Width and Tk_Height instead of width and height.
146          // these values differ by (borderPix) in each dimension.
147    else if (drawMode == NoFlicker) 
148       ResetPrevBarHeights();
149 }
150
151 bool BarChart::TryFirstGoodWid() {
152    // returns true if the wid is valid
153
154    if (!HaveSeenFirstGoodWid) {
155       wid = Tk_WindowId(theWindow);
156       if (wid == 0)
157          return false; // sigh; still invalid
158
159       HaveSeenFirstGoodWid = true;
160
161       // initialize gc
162       XGCValues values;
163       values.foreground = greyColor->pixel;
164       values.background = greyColor->pixel;
165       // values.graphics_exposures = False;
166
167       myGC = XCreateGC(display, wid,
168                        GCForeground | GCBackground,
169                        &values);
170       if (NULL==myGC)
171          panic("BarChart constructor: XCreateGC() failed!");
172
173       // initialize offscreen pixmap
174       if (drawMode == DoubleBuffer)
175          doubleBufferPixmap = XCreatePixmap(display,
176                                             wid, // used only to determine the screen
177                                             Tk_Width(theWindow),
178                                             Tk_Height(theWindow),
179                                             Tk_Depth(theWindow)
180                                             );
181                                          
182       // simulate a resize
183       processResizeWindow();
184    }
185
186    return true;   
187 }
188
189 void BarChart::processResizeWindow() {
190    if (!TryFirstGoodWid())
191       return; // our window is still invalid
192
193    width  = Tk_Width(theWindow) - 2*borderPix; // subtract left+right border
194    height = Tk_Height(theWindow) - 2*borderPix; // subract top+bottom border
195
196    // update off-screen pixmap's dimensions to accomodate the resize
197    changeDoubleBuffering(drawMode==DoubleBuffer, drawMode==NoFlicker);
198
199    RethinkBarLayouts();
200 }
201
202 void BarChart::processExposeWindow() {
203    if (!TryFirstGoodWid())
204       return; // our window is still invalid
205
206    cout << "Welcome to BarChart::processExposeWindow" << endl;
207    if (drawMode == NoFlicker)
208       ResetPrevBarHeights();
209
210    lowLevelDrawBars();
211 }
212
213 char *gimmeColorName(const int metriclcv) {
214    static char *theNames[] = {
215       "blue",
216       "red",
217       "green",
218       "orange"
219    };
220
221    return theNames[metriclcv % 4];
222 }
223
224 void BarChart::RethinkMetricColors() {
225    metricColors.reallocate(numMetrics);
226
227    for (int metriclcv=0; metriclcv<numMetrics; metriclcv++) {
228       XColor *theColor = Tk_GetColor(MainInterp, theWindow, None, Tk_GetUid(gimmeColorName(metriclcv)));
229
230       metricColors[metriclcv] = theColor;
231    }
232 }
233
234 void BarChart::ClearScreen() {
235    XSetForeground(display, myGC, greyColor->pixel);
236    XSetBackground(display, myGC, greyColor->pixel);
237
238    XFillRectangle(display, wid, myGC,
239                   borderPix, // start-x
240                   borderPix, // start-y
241                   width, // this vrble should have already been adjusted re: borderPix
242                   height);
243 }
244
245 void BarChart::ResetPrevBarHeights() {
246    prevBarHeights.reallocate(numMetrics, numResources);
247
248    if (drawMode == NoFlicker) {
249       for (int metriclcv=0; metriclcv<numMetrics; metriclcv++)
250          for (int resourcelcv=0; resourcelcv<numResources; resourcelcv++)
251             prevBarHeights[metriclcv][resourcelcv]=0;
252       if (HaveSeenFirstGoodWid)
253          ClearScreen();
254    }
255 }
256
257 void BarChart::RethinkMetricsAndResources() {
258    // clear window, erase and reallocate barXoffsets, barWidths, prevBarHeights,
259    // barHeights, metricCurrMaxYs; set numMetrics, numResources -- all based on a
260    // complete re-reading from dataGrid[][].  (If visi had provided more fine-grained
261    // callbacks than ADDMETRICSRESOURCES, such a crude routine would not be necessary.)
262
263    // When done, redraw.
264
265    // #include "visualization.h" from visi-lib to get global
266    // variable "dataGrid"
267
268    numMetrics   = dataGrid.NumMetrics();
269    numResources = dataGrid.NumResources();
270
271    cout << "Welcome to BarChart::RethinkMetricsAndResources; m=" << numMetrics << "; r=" << numResources << endl;
272
273    // the following is very unfortunate for existing metric/resource pairs;
274    // their values do not change and so should not be reset.  This is
275    // particularly troublesome for metricCurrMaxYs[], where resetting their
276    // values (as we do here) can be considered a bug.
277    barXoffsets.reallocate(numMetrics, numResources);
278    barWidths  .reallocate(numMetrics, numResources);
279    barHeights .reallocate(numMetrics, numResources);
280    prevBarHeights.reallocate(numMetrics, numResources);
281    barValues  .reallocate(numMetrics, numResources);
282    metricCurrMaxYs.reallocate(numMetrics);
283
284    // reset bar values (very unfortunate for existing pairs)
285    for (int metriclcv=0; metriclcv<numMetrics; metriclcv++)
286       for (int resourcelcv=0; resourcelcv<numResources; resourcelcv++)
287          barValues[metriclcv][resourcelcv]=0;
288
289    // reset max y values (unfortunate for existing pairs)
290    for (metriclcv=0; metriclcv<numMetrics; metriclcv++) {
291       char buffer[64];
292       sprintf(buffer, "%d", metriclcv);
293       char *str = Tcl_GetVar2(MainInterp, "metricMaxValues", buffer, TCL_GLOBAL_ONLY);
294       if (str == NULL)
295          panic("BarChart::RethinkMetricsAndResources() -- could not read 'metricMaxValues'");
296
297       metricCurrMaxYs[metriclcv] = atof(str);
298    }
299
300    RethinkMetricColors(); // reallocates and rethinks metricColors[]
301
302    RethinkBarLayouts(); // as if there were a resize (no reallocations, but
303                         // resets/rethinks barXoffsets[], barWidths[], barHeights[],
304                         // prevBarHeights[])
305
306    if (HaveSeenFirstGoodWid)
307       lowLevelDrawBars();
308 }
309
310 void BarChart::processNewData(int newBucketIndex) {
311    // assuming new data has arrived at the given bucket index for all
312    // metric/rsrc pairs, read the new information from dataGrid[][],
313    // update barHeights[][], barValues[][], and metricCurrMaxYs[] (if needed),
314    // and call lowLevelDrawBars()
315    
316    // PASS 1: Update barValues[][] and check for y-axis overflow, calling
317    //         setMetricNewMaxY() if overflow is detected.
318
319    for (int metriclcv=0; metriclcv<numMetrics; metriclcv++) {
320       visi_GridHistoArray &metricValues = dataGrid[metriclcv];
321
322       for (int resourcelcv=0; resourcelcv<numResources; resourcelcv++) {
323          visi_GridCellHisto &theCell = metricValues[resourcelcv];
324
325          double newVal;
326          switch (DataFormat) {
327             case Current:
328                newVal = theCell.Value(newBucketIndex);
329                break;
330             case Average:
331                // newVal = theCell.AggregateValue(0); // ???
332                newVal = dataGrid.AggregateValue(metriclcv, resourcelcv);
333                break;
334             case Total:
335                // newVal = theCell.SumValue(1); // ???
336                newVal = dataGrid.SumValue(metriclcv, resourcelcv);
337                break;
338             default:
339                assert(false);
340          }
341
342          barValues[metriclcv][resourcelcv] = newVal;
343
344          // the dreaded check for y-axis overflow (slows things down greatly if there
345          // is indeed overflow)
346          double currMaxY = metricCurrMaxYs[metriclcv];
347          if (newVal > currMaxY)
348             setMetricNewMaxY(metriclcv, newVal);
349       }
350    }
351
352    // PASS 2: Now that the y-axis overflows, if any, have been processed, we can
353    //         calculate barHeights with confidence that the scale isn't going to
354    //         change.
355
356    RethinkBarHeights();
357 }
358
359 double BarChart::nicelyRoundedMetricNewYMaxValue(int metricindex, double newmaxval) {
360    assert(0<=metricindex && metricindex<numMetrics);
361
362    char buffer[256];
363    sprintf(buffer, "lindex [getMetricHints %s] 3", dataGrid.MetricName(metricindex));
364
365    if (TCL_OK != Tcl_Eval(MainInterp, buffer))
366       panic("BarChart::nicelyRoundedMetricNewYMaxValue() -- could not eval");
367
368    double hintedStep = atof(MainInterp->result);
369
370    double result = newmaxval + (hintedStep - fmod(newmaxval, hintedStep));
371       // if fmod() doesn't return a number greater than 0, this won't work quite right
372
373    return result;
374 }
375
376 void BarChart::setMetricNewMaxY(int metricindex, double newmaxval) {
377    // given an actual bar value (newmaxval) that overflows the current
378    // y-axis maximum value for the given metric, rethink what the
379    // y-axis maximum value for the given metric should be.
380    // Note that it may not be exactly "newmaxval"; we usually want
381    // to round to a relatively nice number.
382
383    assert(0<=metricindex && metricindex<numMetrics);
384
385    newmaxval = nicelyRoundedMetricNewYMaxValue(metricindex, newmaxval);
386    metricCurrMaxYs[metricindex] = newmaxval;
387
388    char buffer[256];
389    sprintf(buffer, "processNewMetricMax %d %g", metricindex, newmaxval);
390    if (TCL_OK != Tcl_Eval(MainInterp, buffer))
391       cerr << "warning -- BarChart::setMetricNewMaxY() could not inform barChart.tcl of new-max-y-value (no script processNewMetricMax?)" << endl;
392 }
393
394 void BarChart::RethinkBarLayouts() {
395    // assuming a complete resize (but not an added or deleted metric
396    // or resource or even new data values), fill in barXoffsets, barWidths, etc.
397
398    // does not touch metricCurrMaxYs or barValues
399
400    // note: the following loop starts with resources, then does metrics.  should not
401    // cause any big problems, and more intuitive in this case...
402    char *fullResourceWidthStr = Tcl_GetVar(MainInterp, "resourceWidth", TCL_GLOBAL_ONLY);
403    if (NULL == fullResourceWidthStr)
404       panic("BarChart::RethinkBarLayouts() -- could not read 'resourceWidth' from tcl");
405
406    int totalResourceWidth = atoi(fullResourceWidthStr);
407    int fullResourceWidth = (totalResourceWidth * 90) / 100;
408
409    int resourceBorderWidth = (totalResourceWidth - fullResourceWidth) / 2;
410    int individualResourceWidth = (numMetrics == 0) ? 0 : fullResourceWidth / numMetrics;
411
412    for (int resourcelcv=0; resourcelcv<numResources; resourcelcv++) {
413       int left = borderPix + (resourcelcv * totalResourceWidth) + resourceBorderWidth;
414
415       for (int metriclcv=0; metriclcv<numMetrics; metriclcv++) {
416          barXoffsets[metriclcv][resourcelcv] = left + metriclcv * individualResourceWidth;
417          barWidths  [metriclcv][resourcelcv] = individualResourceWidth;
418          barHeights [metriclcv][resourcelcv] = 0; // all bars start off flat
419       }
420    }
421
422    if (drawMode == NoFlicker)
423       ResetPrevBarHeights();
424 }
425
426 void BarChart::RethinkBarHeights() {
427    // set the height of each bar to the fraction of window height
428    // that equals the fraction of the bar's current value to its
429    // metric max y value.
430
431    for (int metriclcv=0; metriclcv<numMetrics; metriclcv++) {
432       for (int resourcelcv=0; resourcelcv<numResources; resourcelcv++) {
433          double theHeight = barValues[metriclcv][resourcelcv] /
434                             metricCurrMaxYs[metriclcv];
435          theHeight *= this->height; // scale by window height (excluding border pixels)
436          barHeights[metriclcv][resourcelcv] = (int)theHeight;
437       }
438    }
439
440    if (HaveSeenFirstGoodWid)
441       lowLevelDrawBars();
442 }
443
444 bool currentlyInstalledLowLevelDrawBars=false;
445
446 void BarChart::lowLevelDrawBars() {
447    // perhaps we should check to see if the barchart program has
448    // been shut down before attempting to do anything?  Nah,
449    // just be sure to call Tk_CancelIdleCall() on lowestLevelDrawBars()
450    // in the destructor.
451
452    isMapped = Tk_IsMapped(theWindow);
453    if (!isMapped)
454       return;
455
456    if (!HaveSeenFirstGoodWid)
457       return;
458
459    if (!currentlyInstalledLowLevelDrawBars) {
460       currentlyInstalledLowLevelDrawBars = true;
461
462       Tk_DoWhenIdle(lowestLevelDrawBars, NULL);
463    }
464 }
465
466 void BarChart::lowestLevelDrawBarsDoubleBuffer() {
467    unsigned long bgPixel = greyColor->pixel;
468
469    // note that the double-buffer pixmap DOES include space for border
470    // pixels, even though we don't make use of such pixels.  This was
471    // done because keeping the offscreen pixmap the same size as the
472    // window simplifies the drawing; e.g. barXoffsets[] already have
473    // borderPix added in to each element and it would be clumsy to
474    // compensate.
475
476    // Our XCopyArea() (when done drawing) is rigged (check the args) to
477    // not copy the border pixel area...
478
479    // clear the offscreen buffer.  XClearArea() works only on windows, so fill a rectangle
480    // with the background color.
481    XSetForeground(display, myGC, bgPixel);
482    XSetBackground(display, myGC, bgPixel);
483    XFillRectangle(display, doubleBufferPixmap,
484                   myGC,
485                   borderPix, // x-offset, relative to drawable
486                   borderPix, // y-offset, relative to drawable
487                   width,     // does not include border pixels
488                   height     // does not include border pixels
489                   );
490
491    if (flushFlag)
492       XSync(display, False);
493
494    // do the drawing onto offscreen pixmap
495    for (int metriclcv=0; metriclcv<numMetrics; metriclcv++) {
496       XSetForeground(display, myGC, metricColors[metriclcv]->pixel);
497    
498       for (int resourcelcv=0; resourcelcv<numResources; resourcelcv++) {
499          XFillRectangle(display,
500                         doubleBufferPixmap,
501                         myGC,
502                         currScrollOffset + barXoffsets[metriclcv][resourcelcv], // left-x
503                         height - barHeights[metriclcv][resourcelcv] - borderPix, // top-y
504                         barWidths[metriclcv][resourcelcv], // width
505                         barHeights[metriclcv][resourcelcv] // height
506                        );
507       }
508    }
509
510    if (flushFlag)
511       XSync(display, False);
512
513    // copy offscreen pixmap onto screen
514    // cout << '{'; cout.flush();
515    
516    XCopyArea(display,
517              doubleBufferPixmap, // source
518              wid,                // dest
519              myGC,
520              borderPix, borderPix, // source x, y (note how we exclude the border)
521              width, height, // these vrbles are preset to exclude the borders
522              borderPix, borderPix // dest x, y (note how we exclude the border)
523             );
524    // cout << '}'; cout.flush();
525
526    if (flushFlag)
527       XSync(display, False);
528 }
529
530 void BarChart::lowestLevelDrawBarsNoFlicker() {
531   // be smart about what gets drawn verses what gets erased; if a bar is lower than
532   // last time, erase the appropriate chunk on top; if a bar is higher than
533   // last time, draw the approrpriate chunk on top.
534   
535   unsigned long bgPixel = greyColor->pixel;
536
537   for (int metriclcv=0; metriclcv<numMetrics; metriclcv++) {
538      unsigned long fgPixel = metricColors[metriclcv]->pixel;
539
540      for (int resourcelcv=0; resourcelcv<numResources; resourcelcv++) {
541         int newHeight = barHeights    [metriclcv][resourcelcv];
542         int oldHeight = prevBarHeights[metriclcv][resourcelcv];
543  
544         if (newHeight > oldHeight) {
545            // the bar is higher than last time; draw the appropriate chunk on top
546            XSetForeground(display, myGC, fgPixel);
547            XSetBackground(display, myGC, bgPixel);
548
549            XFillRectangle(display, wid, myGC,
550                           currScrollOffset + barXoffsets[metriclcv][resourcelcv], // left-x
551                           height - newHeight - borderPix, // top-y
552                           barWidths[metriclcv][resourcelcv], // width
553                           newHeight - oldHeight // height
554                          );
555         }
556         else if (newHeight < oldHeight) {
557            // the bar is lower than last time; erase appropriate chunk on top
558            XSetForeground(display, myGC, bgPixel);
559            XSetBackground(display, myGC, fgPixel);
560
561            XFillRectangle(display, wid, myGC,
562                           currScrollOffset + barXoffsets[metriclcv][resourcelcv], // left-x
563                           height - oldHeight - borderPix, // top-y
564                           barWidths[metriclcv][resourcelcv], // width
565                           oldHeight - newHeight // height
566                           );
567         }
568         else
569             ; // no need to redraw bar at the same height as before
570
571         // and finally...
572         prevBarHeights[metriclcv][resourcelcv] = newHeight;
573      }
574   }
575
576   if (flushFlag)
577      XSync(display, False);
578 }
579
580 void BarChart::lowestLevelDrawBarsFlicker() {
581    ClearScreen(); // clear window, leaving border pixels alone
582    if (flushFlag)
583       XSync(display, False);
584
585    unsigned long bgPixel = greyColor->pixel;
586
587    // do the drawing onto offscreen pixmap
588    for (int metriclcv=0; metriclcv<numMetrics; metriclcv++) {
589       XSetForeground(display, myGC, metricColors[metriclcv]->pixel);
590       XSetBackground(display, myGC, bgPixel);
591    
592       for (int resourcelcv=0; resourcelcv<numResources; resourcelcv++) {
593          XFillRectangle(display, wid,
594                         myGC,
595                         currScrollOffset + barXoffsets[metriclcv][resourcelcv], // left-x
596                         height - barHeights[metriclcv][resourcelcv] - borderPix, // top-y
597                         barWidths[metriclcv][resourcelcv], // width
598                         barHeights[metriclcv][resourcelcv] // height
599                        );
600    
601       }
602    }
603
604    if (flushFlag)
605       XSync(display, False);
606 }
607
608 void BarChart::lowestLevelDrawBars(ClientData ignore) {
609    // cout << '['; cout.flush();
610
611    // NOTE: a --static-- member function --> no "this" exists!!
612
613    if (!theBarChart->HaveSeenFirstGoodWid) {
614       cout << "BarChart::lowestLevelDrawBars -- haven't yet mapped? (ignoring)" << endl;
615       return;
616    }
617
618    currentlyInstalledLowLevelDrawBars = false; // now, new requests will be handled
619       // It seems wrong to delay this line until the bottom of the
620       // routine; it could cause new data to be ignored
621
622    switch (theBarChart->drawMode) {
623       case DoubleBuffer:
624          theBarChart->lowestLevelDrawBarsDoubleBuffer();
625          break;
626       case NoFlicker:
627          theBarChart->lowestLevelDrawBarsNoFlicker();
628          break;
629       case Flicker:
630          theBarChart->lowestLevelDrawBarsFlicker();
631          break;
632       default: assert(0);
633    }
634
635    // cout << ']'; cout.flush();
636 }
637
638 void BarChart::processNewScrollPosition(int newPos) {
639    if (!HaveSeenFirstGoodWid)
640       return;
641
642    // cout << "BarChart::processNewScrollPosition -- new pos=" << newPos << endl;
643
644    // adjust the current x-pixel scroll offset value and
645    // simulate an expose event
646    currScrollOffset = -newPos;
647  
648    // tk is clever with its canvas widgets to never start the leftmost
649    // drawing portion at less than 0; we must be just as clever to keep
650    // everything positioned correctly.
651 //   if (currScrollOffset < 0 && scrollbarisfullwidth)
652 //      currScrollOffset=0;
653
654    if (drawMode == NoFlicker)
655       ResetPrevBarHeights();
656
657    lowLevelDrawBars();
658 }
659
660 void BarChart::rethinkDataFormat() {
661    // assuming the data format has changed, read its
662    // value (from tcl) and adjust our internal settings accordingly.
663
664    char *dataFormatString = Tcl_GetVar(MainInterp, "DataFormat", TCL_GLOBAL_ONLY);
665    if (dataFormatString == NULL) {
666       cerr << "warning: BarChart::rethinkDataFormat() -- could not read tcl vrble 'DataFormat'; ignoring" << endl;
667       return;
668    }
669
670    if (0==strcmp(dataFormatString, "Instantaneous"))
671       DataFormat = Current;
672    else if (0==strcmp(dataFormatString, "Average"))
673       DataFormat = Average;
674    else if (0==strcmp(dataFormatString, "Sum"))
675       DataFormat = Total;
676    else {
677       cerr << "BarChart::rethinkDataFormat() -- unrecognized format '"
678            << dataFormatString << "'; ignoring" << endl;
679       return;
680    }
681
682    // we have changed the data format.  The max y-values need
683    // to be "re-thought" (else, what if we change from total to current;
684    // the max y value will be so high and won't ever get lowered)
685    RethinkMetricsAndResources();
686       // a bit more than is really needed!
687 }