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