1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkChartBox.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 
16 #include "vtkChartBox.h"
17 
18 #include "vtkAnnotationLink.h"
19 #include "vtkAxis.h"
20 #include "vtkBrush.h"
21 #include "vtkCommand.h"
22 #include "vtkContext2D.h"
23 #include "vtkContextScene.h"
24 #include "vtkContextMapper2D.h"
25 #include "vtkContextMouseEvent.h"
26 #include "vtkDataArray.h"
27 #include "vtkIdTypeArray.h"
28 #include "vtkNew.h"
29 #include "vtkObjectFactory.h"
30 #include "vtkPen.h"
31 #include "vtkPlotBox.h"
32 #include "vtkPlotGrid.h"
33 #include "vtkPoints2D.h"
34 #include "vtkSelection.h"
35 #include "vtkSelectionNode.h"
36 #include "vtkSmartPointer.h"
37 #include "vtkStringArray.h"
38 #include "vtkTable.h"
39 #include "vtkTextProperty.h"
40 #include "vtkTooltipItem.h"
41 #include "vtkTransform2D.h"
42 
43 #include <algorithm>
44 #include <vector>
45 
46 
47 // Minimal storage class for STL containers etc.
48 class vtkChartBox::Private
49 {
50 public:
Private()51   Private()
52   {
53     this->Plot = vtkSmartPointer<vtkPlotBox>::New();
54     this->YAxis->SetPosition(vtkAxis::LEFT);
55     this->YAxis->SetPoint1(0, 0);
56     this->YAxis->SetTitle("Y");
57   }
58   ~Private() = default;
59   vtkSmartPointer<vtkPlotBox> Plot;
60   std::vector<float> XPosition;
61   vtkNew<vtkTransform2D> Transform;
62   vtkNew<vtkAxis> YAxis;
63   vtkNew<vtkPlotGrid> Grid;
64   float SelectedColumnDelta;
65 };
66 
67 //-----------------------------------------------------------------------------
68 
69 //-----------------------------------------------------------------------------
70 vtkStandardNewMacro(vtkChartBox);
71 
72 //-----------------------------------------------------------------------------
vtkChartBox()73 vtkChartBox::vtkChartBox()
74 {
75   this->Storage = new vtkChartBox::Private;
76   this->Storage->Plot->SetParent(this);
77   this->AddItem(this->Storage->YAxis);
78   this->GeometryValid = false;
79   this->Selection = vtkIdTypeArray::New();
80   this->SelectedColumn = -1;
81   this->Storage->Plot->SetSelection(this->Selection);
82   this->VisibleColumns = vtkStringArray::New();
83 
84   this->Tooltip = vtkSmartPointer<vtkTooltipItem>::New();
85   this->Tooltip->SetVisible(false);
86   this->AddItem(this->Tooltip);
87 
88   // Set up default mouse button assignments for parallel coordinates.
89   this->SetActionToButton(vtkChart::PAN, vtkContextMouseEvent::RIGHT_BUTTON);
90   this->SetActionToButton(vtkChart::SELECT, vtkContextMouseEvent::LEFT_BUTTON);
91 }
92 
93 //-----------------------------------------------------------------------------
~vtkChartBox()94 vtkChartBox::~vtkChartBox()
95 {
96   this->Storage->Plot->SetSelection(nullptr);
97   delete this->Storage;
98   this->Selection->Delete();
99   this->VisibleColumns->Delete();
100 }
101 
102 //-----------------------------------------------------------------------------
Update()103 void vtkChartBox::Update()
104 {
105   vtkTable* table = this->Storage->Plot->GetData()->GetInput();
106   if (!table)
107   {
108     return;
109   }
110 
111   if (table->GetMTime() < this->BuildTime && this->MTime < this->BuildTime)
112   {
113     return;
114   }
115 
116   int nbCols = this->VisibleColumns->GetNumberOfTuples();
117 
118   this->Storage->XPosition.resize(nbCols);
119 
120   double grange[2] = { VTK_DOUBLE_MAX, VTK_DOUBLE_MIN };
121   // Now set up their ranges and locations
122   for (int i = 0; i < nbCols; ++i)
123   {
124     vtkDataArray* array =
125       vtkArrayDownCast<vtkDataArray>(table->GetColumnByName(
126     this->VisibleColumns->GetValue(i)));
127     if (array)
128     {
129       double range[2];
130       array->GetRange(range);
131       if (range[0] < grange[0])
132       {
133         grange[0] = range[0];
134       }
135       if (range[1] > grange[1])
136       {
137         grange[1] = range[1];
138       }
139     }
140   }
141 
142   this->Storage->YAxis->SetMinimum(grange[0]);
143   this->Storage->YAxis->SetMaximum(grange[1]);
144 
145   this->GeometryValid = false;
146   this->BuildTime.Modified();
147 }
148 
149 //-----------------------------------------------------------------------------
Paint(vtkContext2D * painter)150 bool vtkChartBox::Paint(vtkContext2D *painter)
151 {
152   if (this->GetScene()->GetViewWidth() == 0 ||
153       this->GetScene()->GetViewHeight() == 0 ||
154       !this->Visible || !this->Storage->Plot->GetVisible() ||
155       this->VisibleColumns->GetNumberOfTuples() < 1)
156   {
157     // The geometry of the chart must be valid before anything can be drawn
158     return false;
159   }
160 
161   //this->UpdateGeometry(painter);
162   this->Update();
163   this->UpdateGeometry(painter);
164 
165   // Handle selections
166   vtkIdTypeArray *idArray = nullptr;
167   if (this->AnnotationLink)
168   {
169     vtkSelection *selection = this->AnnotationLink->GetCurrentSelection();
170     if (selection->GetNumberOfNodes() &&
171         this->AnnotationLink->GetMTime() > this->Storage->Plot->GetMTime())
172     {
173       vtkSelectionNode *node = selection->GetNode(0);
174       idArray = vtkArrayDownCast<vtkIdTypeArray>(node->GetSelectionList());
175       this->Storage->Plot->SetSelection(idArray);
176     }
177   }
178   else
179   {
180     vtkDebugMacro("No annotation link set.");
181   }
182 
183   painter->PushMatrix();
184   painter->SetTransform(this->Storage->Transform);
185   this->Storage->Plot->Paint(painter);
186   painter->PopMatrix();
187 
188   this->Storage->YAxis->Paint(painter);
189 
190   if (this->Title)
191   {
192     painter->ApplyTextProp(this->TitleProperties);
193     vtkVector2f stringBounds[2];
194     painter->ComputeStringBounds(this->Title, stringBounds->GetData());
195     float height = 1.1 * stringBounds[1].GetY();
196 
197     // Shift the position of the title down if it would be outside the window
198     float shift;
199     if (this->Point2[1] + height > this->Geometry[1])
200     {
201       shift = this->Point2[1] + height - this->Geometry[1];
202     }
203     else
204     {
205       shift = 0.0f;
206     }
207     vtkPoints2D *rect = vtkPoints2D::New();
208     rect->InsertNextPoint(this->Point1[0],
209                           this->Point2[1]);
210     rect->InsertNextPoint(this->Point2[0]-this->Point1[0],
211                           height - shift);
212     painter->DrawStringRect(rect, this->Title);
213     rect->Delete();
214   }
215 
216   if (this->GetShowLegend())
217   {
218     vtkRectf rect;
219     rect.Set(0, 2, 10, 20);
220     this->Storage->Plot->PaintLegend(painter, rect, 0);
221   }
222 
223   if (this->Tooltip && this->Tooltip->GetVisible())
224   {
225     this->Tooltip->Paint(painter);
226   }
227 
228   return true;
229 }
230 
231 //-----------------------------------------------------------------------------
SetColumnVisibility(const vtkStdString & name,bool visible)232 void vtkChartBox::SetColumnVisibility(const vtkStdString& name,
233                                       bool visible)
234 {
235   if (visible)
236   {
237     for (vtkIdType i = 0; i < this->VisibleColumns->GetNumberOfTuples(); ++i)
238     {
239       if (this->VisibleColumns->GetValue(i) == name)
240       {
241         // Already there, nothing more needs to be done
242         return;
243       }
244     }
245     // Add the column to the end of the list
246     this->VisibleColumns->InsertNextValue(name);
247     this->Modified();
248     this->Update();
249   }
250   else
251   {
252     // Remove the value if present
253     for (vtkIdType i = 0; i < this->VisibleColumns->GetNumberOfTuples(); ++i)
254     {
255       if (this->VisibleColumns->GetValue(i) == name)
256       {
257         // Move all the later elements down by one, and reduce the size
258         while (i < this->VisibleColumns->GetNumberOfTuples()-1)
259         {
260           this->VisibleColumns->SetValue(i, this->VisibleColumns->GetValue(i+1));
261           ++i;
262         }
263         this->VisibleColumns->SetNumberOfTuples(
264             this->VisibleColumns->GetNumberOfTuples()-1);
265         if (this->SelectedColumn >= this->VisibleColumns->GetNumberOfTuples())
266         {
267           this->SelectedColumn = -1;
268         }
269         this->Modified();
270         this->Update();
271         return;
272       }
273     }
274   }
275 }
276 
277 //-----------------------------------------------------------------------------
SetColumnVisibility(vtkIdType column,bool visible)278 void vtkChartBox::SetColumnVisibility(vtkIdType column, bool visible)
279 {
280   vtkPlot *plot = this->GetPlot(0);
281   if (!plot || !plot->GetInput())
282   {
283     return;
284   }
285   vtkTable *table = plot->GetInput();
286   if (table)
287   {
288     this->SetColumnVisibility(table->GetColumnName(column), visible);
289   }
290 }
291 
292 //-----------------------------------------------------------------------------
SetColumnVisibilityAll(bool visible)293 void vtkChartBox::SetColumnVisibilityAll(bool visible)
294 {
295   // We always need to clear the current visible columns.
296   this->VisibleColumns->SetNumberOfTuples(0);
297   this->SelectedColumn = -1;
298   if (visible)
299   {
300     vtkPlot *plot = this->GetPlot(0);
301     if (!plot || !plot->GetInput())
302     {
303       return;
304     }
305     vtkTable *table = plot->GetInput();
306     for (vtkIdType i = 0; i < table->GetNumberOfColumns(); ++i)
307     {
308       this->SetColumnVisibility(table->GetColumnName(i), visible);
309     }
310   }
311 }
312 
313 //-----------------------------------------------------------------------------
GetColumnVisibility(const vtkStdString & name)314 bool vtkChartBox::GetColumnVisibility(const vtkStdString& name)
315 {
316   for (vtkIdType i = 0; i < this->VisibleColumns->GetNumberOfTuples(); ++i)
317   {
318     if (this->VisibleColumns->GetValue(i) == name)
319     {
320       return true;
321     }
322   }
323   return false;
324 }
325 
326 //-----------------------------------------------------------------------------
GetColumnVisibility(vtkIdType column)327 bool vtkChartBox::GetColumnVisibility(vtkIdType column)
328 {
329   vtkPlot *plot = this->GetPlot(0);
330   if (!plot || !plot->GetInput())
331   {
332     return false;
333   }
334   vtkTable *table = plot->GetInput();
335   return this->GetColumnVisibility(table->GetColumnName(column));
336 }
337 
338 //-----------------------------------------------------------------------------
GetNumberOfVisibleColumns()339 vtkIdType vtkChartBox::GetNumberOfVisibleColumns()
340 {
341   return this->VisibleColumns->GetNumberOfTuples();
342 }
343 
344 //-----------------------------------------------------------------------------
GetColumnId(const vtkStdString & name)345 vtkIdType vtkChartBox::GetColumnId(const vtkStdString& name)
346 {
347   vtkPlot *plot = this->GetPlot(0);
348   if (!plot || !plot->GetInput())
349   {
350     return -1;
351   }
352   vtkTable *table = plot->GetInput();
353   vtkIdType nbColumn = table->GetNumberOfColumns();
354   for (vtkIdType i = 0; i < nbColumn; i++)
355   {
356     if (!strcmp(table->GetColumnName(i), name.c_str()))
357     {
358       return i;
359     }
360   }
361   return -1;
362 }
363 
364 //-----------------------------------------------------------------------------
GetYAxis()365 vtkAxis* vtkChartBox::GetYAxis()
366 {
367   return this->Storage->YAxis;
368 }
369 
370 //-----------------------------------------------------------------------------
SetPlot(vtkPlotBox * plot)371 void vtkChartBox::SetPlot(vtkPlotBox *plot)
372 {
373   this->Storage->Plot = plot;
374   this->Storage->Plot->SetParent(this);
375   this->Modified();
376 }
377 
378 //-----------------------------------------------------------------------------
GetPlot(vtkIdType)379 vtkPlot* vtkChartBox::GetPlot(vtkIdType)
380 {
381   return this->Storage->Plot;
382 }
383 
384 //-----------------------------------------------------------------------------
GetNumberOfPlots()385 vtkIdType vtkChartBox::GetNumberOfPlots()
386 {
387   return 1;
388 }
389 
390 //-----------------------------------------------------------------------------
GetXPosition(int index)391 float vtkChartBox::GetXPosition(int index)
392 {
393   return (index < static_cast<int>(this->Storage->XPosition.size())) ?
394     this->Storage->XPosition[index] : 0;
395 }
396 
397 //-----------------------------------------------------------------------------
UpdateGeometry(vtkContext2D * painter)398 void vtkChartBox::UpdateGeometry(vtkContext2D* painter)
399 {
400   vtkVector2i geometry(this->GetScene()->GetViewWidth(),
401                        this->GetScene()->GetViewHeight());
402 
403   if (geometry.GetX() != this->Geometry[0] ||
404     geometry.GetY() != this->Geometry[1] || !this->GeometryValid)
405   {
406     vtkAxis* axis = this->Storage->YAxis;
407 
408     axis->SetPoint1(0, this->Point1[1]);
409     axis->SetPoint2(0, this->Point2[1]);
410     if (axis->GetBehavior() == 0)
411     {
412       axis->AutoScale();
413     }
414     axis->Update();
415 
416     int leftBorder = 0;
417     if (axis->GetVisible())
418     {
419       vtkRectf bounds = axis->GetBoundingRect(painter);
420       leftBorder = int(bounds.GetWidth());
421     }
422     axis->SetPoint1(leftBorder, this->Point1[1]);
423     axis->SetPoint2(leftBorder, this->Point2[1]);
424 
425     // Take up the entire window right now, this could be made configurable
426     this->SetGeometry(geometry.GetData());
427 
428     vtkVector2i tileScale = this->Scene->GetLogicalTileScale();
429     this->SetBorders(leftBorder, 30 * tileScale.GetY(),
430                      0, 20 * tileScale.GetY());
431 
432     int nbPlots = static_cast<int>(this->Storage->XPosition.size());
433     // Iterate through the axes and set them up to span the chart area.
434     int xStep = (this->Point2[0] - this->Point1[0]) / nbPlots;
435     int x = this->Point1[0] + (xStep / 2);
436 
437     for (int i = 0; i < nbPlots; ++i)
438     {
439       this->Storage->XPosition[i] = x;
440 
441       x += xStep;
442     }
443     this->GeometryValid = true;
444 
445     // Cause the plot transform to be recalculated if necessary
446     this->CalculatePlotTransform();
447 
448     if (this->VisibleColumns->GetNumberOfValues() > 1)
449     {
450       this->Storage->Plot->SetBoxWidth(0.5f *
451         (this->GetXPosition(1) - this->GetXPosition(0)));
452     }
453 
454     this->Storage->Plot->Update();
455   }
456 }
457 
458 //-----------------------------------------------------------------------------
CalculatePlotTransform()459 void vtkChartBox::CalculatePlotTransform()
460 {
461   // In the case of box plots everything is plotted in a normalized
462   // system, where the range is from 0.0 to 1.0 in the y axis, and in screen
463   // coordinates along the x axis.
464   vtkAxis* axis = this->Storage->YAxis;
465   float *min = axis->GetPoint1();
466   float *max = axis->GetPoint2();
467   float yScale = 1.0f / (max[1] - min[1]);
468 
469   this->Storage->Transform->Identity();
470   this->Storage->Transform->Translate(0, axis->GetPoint1()[1]);
471   // Get the scale for the plot area from the x and y axes
472   this->Storage->Transform->Scale(1.0, 1.0 / yScale);
473 }
474 
475 //-----------------------------------------------------------------------------
Hit(const vtkContextMouseEvent & mouse)476 bool vtkChartBox::Hit(const vtkContextMouseEvent &mouse)
477 {
478   vtkVector2i pos(mouse.GetScreenPos());
479   float width = this->Storage->Plot->GetBoxWidth() / 2.f;
480   return
481     pos[0] > this->Point1[0] - width &&
482     pos[0] < this->Point2[0] + width &&
483     pos[1] > this->Point1[1] &&
484     pos[1] < this->Point2[1];
485 }
486 
487 //-----------------------------------------------------------------------------
MouseMoveEvent(const vtkContextMouseEvent & mouse)488 bool vtkChartBox::MouseMoveEvent(const vtkContextMouseEvent &mouse)
489 {
490   if (mouse.GetButton() == this->Actions.Pan() && this->SelectedColumn >= 0)
491   {
492     if (this->Tooltip)
493     {
494       this->Tooltip->SetVisible(false);
495     }
496 
497     // Move the plot in x
498     float posX = mouse.GetScenePos().GetX() + this->SelectedColumnDelta;
499     this->Storage->XPosition[this->SelectedColumn] = posX;
500 
501     int nbCols = static_cast<int>(this->Storage->XPosition.size());
502     int left = this->SelectedColumn - 1;
503     int right = this->SelectedColumn + 1;
504 
505     float width = this->Storage->Plot->GetBoxWidth() * 0.5f;
506 
507     if (left >= 0 && (posX - width) < this->Storage->XPosition[left])
508     {
509       this->SwapAxes(this->SelectedColumn, this->SelectedColumn - 1);
510       this->SelectedColumn--;
511     }
512     else if (right < nbCols && (posX + width) > this->Storage->XPosition[right])
513     {
514       this->SwapAxes(this->SelectedColumn, this->SelectedColumn + 1);
515       this->SelectedColumn++;
516     }
517     this->Scene->SetDirty(true);
518     this->Storage->XPosition[this->SelectedColumn] = posX;
519   }
520 
521   if (mouse.GetButton() == vtkContextMouseEvent::NO_BUTTON)
522   {
523     this->Scene->SetDirty(true);
524 
525     if (this->Tooltip)
526     {
527       this->Tooltip->SetVisible(this->LocatePointInPlots(mouse));
528     }
529   }
530   return true;
531 }
532 
533 //-----------------------------------------------------------------------------
MouseButtonPressEvent(const vtkContextMouseEvent & mouse)534 bool vtkChartBox::MouseButtonPressEvent(const vtkContextMouseEvent& mouse)
535 {
536   if (mouse.GetButton() == this->Actions.Pan())
537   {
538     // Select a plot if we are within range
539     if (mouse.GetScenePos()[1] > this->Point1[1] &&
540         mouse.GetScenePos()[1] < this->Point2[1])
541     {
542       // Iterate over the axes, see if we are within 10 pixels of an axis
543       for (size_t i = 0; i < this->Storage->XPosition.size(); ++i)
544       {
545         float selX = this->Storage->XPosition[i];
546         float width = this->Storage->Plot->GetBoxWidth() / 2.f;
547         if (selX - width < mouse.GetScenePos()[0] &&
548             selX + width > mouse.GetScenePos()[0])
549         {
550           this->SelectedColumn = static_cast<int>(i);
551           this->SelectedColumnDelta =
552             this->GetXPosition(this->SelectedColumn) - mouse.GetScenePos().GetX();
553           this->Scene->SetDirty(true);
554           return true;
555         }
556       }
557     }
558     this->SelectedColumn = -1;
559     this->Scene->SetDirty(true);
560     return true;
561   }
562 
563   return false;
564 }
565 
566 //-----------------------------------------------------------------------------
MouseButtonReleaseEvent(const vtkContextMouseEvent & mouse)567 bool vtkChartBox::MouseButtonReleaseEvent(const vtkContextMouseEvent& mouse)
568 {
569   this->SelectedColumn = -1;
570   if (mouse.GetButton() == this->Actions.Select())
571   {
572     if (this->SelectedColumn >= 0)
573     {
574       if (this->AnnotationLink)
575       {
576         vtkSelection* selection = vtkSelection::New();
577         vtkSelectionNode* node = vtkSelectionNode::New();
578         selection->AddNode(node);
579         node->SetContentType(vtkSelectionNode::INDICES);
580         node->SetFieldType(vtkSelectionNode::POINT);
581 
582         node->SetSelectionList(this->Storage->Plot->GetSelection());
583         this->AnnotationLink->SetCurrentSelection(selection);
584         selection->Delete();
585         node->Delete();
586       }
587       this->InvokeEvent(vtkCommand::SelectionChangedEvent);
588       this->Scene->SetDirty(true);
589     }
590     return true;
591   }
592   else if (mouse.GetButton() == this->Actions.Pan())
593   {
594     this->GeometryValid = false;
595     this->SelectedColumn = -1;
596     return true;
597   }
598   this->Scene->SetDirty(true);
599   return true;
600 }
601 
602 //-----------------------------------------------------------------------------
LocatePointInPlot(const vtkVector2f & position,const vtkVector2f & tolerance,vtkVector2f & plotPos,vtkPlot * plot,vtkIdType &)603 int vtkChartBox::LocatePointInPlot(const vtkVector2f &position,
604                                    const vtkVector2f &tolerance,
605                                    vtkVector2f &plotPos,
606                                    vtkPlot *plot,
607                                    vtkIdType &)
608 {
609   if (plot && plot->GetVisible())
610   {
611     vtkPlotBox* plotBar = vtkPlotBox::SafeDownCast(plot);
612     if (plotBar)
613     {
614       // If the plot is a vtkPlotBar, get the segment index too
615       return plotBar->GetNearestPoint(position, tolerance,
616                                       &plotPos);
617     }
618     else
619     {
620       return plot->GetNearestPoint(position, tolerance, &plotPos);
621     }
622   }
623   return -1;
624 }
625 
626 //-----------------------------------------------------------------------------
LocatePointInPlots(const vtkContextMouseEvent & mouse,int invokeEvent)627 bool vtkChartBox::LocatePointInPlots(const vtkContextMouseEvent &mouse,
628                                      int invokeEvent)
629 {
630   vtkVector2i pos(mouse.GetScreenPos());
631   if (pos[0] > this->Point1[0] &&
632       pos[0] < this->Point2[0] &&
633       pos[1] > this->Point1[1] &&
634       pos[1] < this->Point2[1])
635   {
636     vtkVector2f plotPos, position;
637     vtkTransform2D* transform =
638       this->Storage->Transform;
639     transform->InverseTransformPoints(mouse.GetPos().GetData(),
640       position.GetData(), 1);
641     // Use a tolerance of +/- 5 pixels
642     vtkVector2f tolerance(5*(1.0/transform->GetMatrix()->GetElement(0, 0)),
643       5*(1.0/transform->GetMatrix()->GetElement(1, 1)));
644 
645     vtkPlot* plot = this->Storage->Plot;
646     vtkIdType segmentIndex = -1;
647     int seriesIndex =
648       LocatePointInPlot(position, tolerance, plotPos, plot, segmentIndex);
649 
650     if (seriesIndex >= 0)
651     {
652       // We found a point, set up the tooltip and return
653       vtkRectd ss(plot->GetShiftScale());
654       vtkVector2d plotPosd(plotPos[0] / ss[2] - ss[0],
655         plotPos[1] / ss[3] - ss[1]);
656       this->SetTooltipInfo(mouse, plotPosd, seriesIndex, plot,
657         segmentIndex);
658       if (invokeEvent >= 0)
659       {
660         vtkChartBoxData plotIndex;
661         plotIndex.SeriesName =
662           this->GetVisibleColumns()->GetValue(seriesIndex);
663         plotIndex.Position = plotPos;
664         plotIndex.ScreenPosition = mouse.GetScreenPos();
665         plotIndex.Index = segmentIndex;
666         // Invoke an event, with the client data supplied
667         this->InvokeEvent(invokeEvent, static_cast<void*>(&plotIndex));
668       }
669       return true;
670     }
671   }
672   return false;
673 }
674 
675 //-----------------------------------------------------------------------------
SetTooltip(vtkTooltipItem * tooltip)676 void vtkChartBox::SetTooltip(vtkTooltipItem *tooltip)
677 {
678   if (tooltip == this->Tooltip)
679   {
680     // nothing to change
681     return;
682   }
683 
684   if (this->Tooltip)
685   {
686     // remove current tooltip from scene
687     this->RemoveItem(this->Tooltip);
688   }
689 
690   this->Tooltip = tooltip;
691 
692   if (this->Tooltip)
693   {
694     // add new tooltip to scene
695     this->AddItem(this->Tooltip);
696   }
697 }
698 
699 //-----------------------------------------------------------------------------
GetTooltip()700 vtkTooltipItem* vtkChartBox::GetTooltip()
701 {
702   return this->Tooltip;
703 }
704 
705 //-----------------------------------------------------------------------------
SetTooltipInfo(const vtkContextMouseEvent & mouse,const vtkVector2d & plotPos,vtkIdType seriesIndex,vtkPlot * plot,vtkIdType segmentIndex)706 void vtkChartBox::SetTooltipInfo(const vtkContextMouseEvent& mouse,
707                                  const vtkVector2d &plotPos,
708                                  vtkIdType seriesIndex, vtkPlot* plot,
709                                  vtkIdType segmentIndex)
710 {
711   if (!this->Tooltip)
712   {
713     return;
714   }
715 
716   // Have the plot generate its tooltip label
717   vtkStdString tooltipLabel = plot->GetTooltipLabel(plotPos, seriesIndex,
718                                                     segmentIndex);
719 
720   // Set the tooltip
721   this->Tooltip->SetText(tooltipLabel);
722   this->Tooltip->SetPosition(mouse.GetScreenPos()[0] + 2,
723                              mouse.GetScreenPos()[1] + 2);
724 }
725 
726 //-----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)727 void vtkChartBox::PrintSelf(ostream &os, vtkIndent indent)
728 {
729   this->Superclass::PrintSelf(os, indent);
730 }
731 
732 //-----------------------------------------------------------------------------
SwapAxes(int a1,int a2)733 void vtkChartBox::SwapAxes(int a1, int a2)
734 {
735   vtkStdString colTmp = this->VisibleColumns->GetValue(a1);
736   this->VisibleColumns->SetValue(a1, this->VisibleColumns->GetValue(a2));
737   this->VisibleColumns->SetValue(a2, colTmp);
738 
739   int xStep = (this->Point2[0] - this->Point1[0]) /
740                 (static_cast<int>(this->Storage->XPosition.size()));
741   int xPos = (this->Point1[0] + (xStep / 2)) + xStep * a1;
742   this->Storage->XPosition[a1] = xPos;
743 
744   this->GeometryValid = true;
745 
746   this->Storage->Plot->Update();
747 }
748