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