1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkPlotRangeHandlesItem.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 "vtkPlotRangeHandlesItem.h"
17 
18 #include "vtkAxis.h"
19 #include "vtkBrush.h"
20 #include "vtkColorTransferFunction.h"
21 #include "vtkCommand.h"
22 #include "vtkContext2D.h"
23 #include "vtkContextMouseEvent.h"
24 #include "vtkContextScene.h"
25 #include "vtkObjectFactory.h"
26 #include "vtkPen.h"
27 #include "vtkRenderWindow.h"
28 #include "vtkRenderer.h"
29 #include "vtkTextProperty.h"
30 #include "vtkTransform2D.h"
31 
32 #include <sstream>
33 
34 //------------------------------------------------------------------------------
35 vtkStandardNewMacro(vtkPlotRangeHandlesItem);
36 
37 //------------------------------------------------------------------------------
vtkPlotRangeHandlesItem()38 vtkPlotRangeHandlesItem::vtkPlotRangeHandlesItem()
39 {
40   this->Brush->SetColor(125, 135, 144, 200);
41   this->HighlightBrush->SetColor(255, 0, 255, 200);
42   this->RangeLabelBrush->SetColor(255, 255, 255, 200);
43 }
44 
45 //------------------------------------------------------------------------------
46 vtkPlotRangeHandlesItem::~vtkPlotRangeHandlesItem() = default;
47 
48 //------------------------------------------------------------------------------
ComputeHandlesDrawRange()49 void vtkPlotRangeHandlesItem::ComputeHandlesDrawRange()
50 {
51   double screenBounds[4];
52   this->GetBounds(screenBounds);
53   this->ComputeHandleDelta(screenBounds);
54   double range[2];
55   this->GetHandlesRange(range);
56 
57   double unused;
58   this->TransformDataToScreen(range[0], 1, range[0], unused);
59   this->TransformDataToScreen(range[1], 1, range[1], unused);
60 
61   this->ComputeRange(range);
62 }
63 
64 //------------------------------------------------------------------------------
ComputeRange(double * range)65 void vtkPlotRangeHandlesItem::ComputeRange(double* range)
66 {
67   if (this->ActiveHandle == vtkPlotRangeHandlesItem::LEFT_HANDLE)
68   {
69     double previousLeftValue = this->LeftHandleDrawRange[0];
70     this->LeftHandleDrawRange[0] = this->ActiveHandlePosition - this->HandleDelta;
71     this->LeftHandleDrawRange[1] = this->ActiveHandlePosition + this->HandleDelta;
72     if (this->SynchronizeRangeHandles)
73     {
74       double leftShift = this->LeftHandleDrawRange[0] - previousLeftValue;
75       this->RightHandleDrawRange[0] += leftShift;
76       this->RightHandleDrawRange[1] += leftShift;
77       return;
78     }
79   }
80   else
81   {
82     this->LeftHandleDrawRange[0] = range[0];
83     this->LeftHandleDrawRange[1] = range[0] + 2.0 * this->HandleDelta;
84   }
85 
86   if (this->ActiveHandle == vtkPlotRangeHandlesItem::RIGHT_HANDLE)
87   {
88     this->RightHandleDrawRange[0] = this->ActiveHandlePosition - this->HandleDelta;
89     this->RightHandleDrawRange[1] = this->ActiveHandlePosition + this->HandleDelta;
90   }
91   else
92   {
93     this->RightHandleDrawRange[0] = range[1];
94     this->RightHandleDrawRange[1] = range[1] - 2.0 * this->HandleDelta;
95   }
96 }
97 
98 //------------------------------------------------------------------------------
ComputeHandleDelta(double screenBounds[4])99 void vtkPlotRangeHandlesItem::ComputeHandleDelta(double screenBounds[4])
100 {
101   // Try to use the scene to produce correctly size handles
102   double width = 400.0;
103   vtkContextScene* scene = this->GetScene();
104   if (scene && scene->GetSceneWidth() > 0 && scene->GetSceneHeight() > 0)
105   {
106     if (this->HandleOrientation == vtkPlotRangeHandlesItem::VERTICAL)
107     {
108       width = static_cast<double>(scene->GetSceneWidth());
109     }
110     else // HORIZONTAL
111     {
112       width = static_cast<double>(scene->GetSceneHeight());
113     }
114   }
115 
116   this->HandleDelta =
117     this->HandleWidth * static_cast<float>((screenBounds[1] - screenBounds[0]) / width);
118 }
119 
120 //------------------------------------------------------------------------------
Paint(vtkContext2D * painter)121 bool vtkPlotRangeHandlesItem::Paint(vtkContext2D* painter)
122 {
123   if (!this->Visible)
124   {
125     return false;
126   }
127 
128   vtkNew<vtkPen> transparentPen;
129   transparentPen->SetLineType(vtkPen::NO_PEN);
130   painter->ApplyPen(transparentPen);
131 
132   // Compute handles draw range
133   this->ComputeHandlesDrawRange();
134 
135   int highlightedHandle = this->ActiveHandle;
136   if (highlightedHandle == vtkPlotRangeHandlesItem::NO_HANDLE)
137   {
138     highlightedHandle = this->HoveredHandle;
139   }
140 
141   // Draw Left Handle
142   if (highlightedHandle == vtkPlotRangeHandlesItem::LEFT_HANDLE)
143   {
144     painter->ApplyBrush(this->HighlightBrush);
145   }
146   else
147   {
148     painter->ApplyBrush(this->Brush);
149   }
150 
151   double length[2] = { this->Extent[2], this->Extent[3] };
152   if (this->ExtentToAxisRange)
153   {
154     double screenBounds[4];
155     this->GetBounds(screenBounds);
156     length[0] = screenBounds[2];
157     length[1] = screenBounds[3];
158   }
159 
160   if (this->HandleOrientation == vtkPlotRangeHandlesItem::VERTICAL)
161   {
162     painter->DrawQuad(this->LeftHandleDrawRange[0], length[0], this->LeftHandleDrawRange[0],
163       length[1], this->LeftHandleDrawRange[1], length[1], this->LeftHandleDrawRange[1], length[0]);
164   }
165   else // HORIZONTAL
166   {
167     painter->DrawQuad(length[0], this->LeftHandleDrawRange[0], length[1],
168       this->LeftHandleDrawRange[0], length[1], this->LeftHandleDrawRange[1], length[0],
169       this->LeftHandleDrawRange[1]);
170   }
171 
172   // Draw Right Handle
173   if (highlightedHandle == vtkPlotRangeHandlesItem::RIGHT_HANDLE)
174   {
175     painter->ApplyBrush(this->HighlightBrush);
176   }
177   else
178   {
179     painter->ApplyBrush(this->Brush);
180   }
181 
182   if (this->HandleOrientation == vtkPlotRangeHandlesItem::VERTICAL)
183   {
184     painter->DrawQuad(this->RightHandleDrawRange[0], length[0], this->RightHandleDrawRange[0],
185       length[1], this->RightHandleDrawRange[1], length[1], this->RightHandleDrawRange[1],
186       length[0]);
187   }
188   else // HORIZONTAL
189   {
190     painter->DrawQuad(length[0], this->RightHandleDrawRange[0], length[1],
191       this->RightHandleDrawRange[0], length[1], this->RightHandleDrawRange[1], length[0],
192       this->RightHandleDrawRange[1]);
193   }
194 
195   // Draw range info
196   if (highlightedHandle != vtkPlotRangeHandlesItem::NO_HANDLE)
197   {
198     this->InvokeEvent(vtkCommand::HighlightEvent);
199     double range[2];
200     this->GetHandlesRange(range);
201     std::stringstream label;
202     label << "Range : [" << this->GetNumber(range[0], nullptr) << ", "
203           << this->GetNumber(range[1], nullptr) << "]";
204 
205     vtkVector2f labelBounds[2];
206     painter->ComputeStringBounds(label.str(), labelBounds[0].GetData());
207 
208     float labelStartX = this->HoveredPosition[0] - labelBounds[1].GetX() / 2.0f;
209     float labelStartY = this->HoveredPosition[1] - labelBounds[1].GetY() * 2.0f;
210 
211     // When the tooltip is not locked to the mouse position, place it at the
212     // middle of the X axis.
213     if (!this->LockTooltipToMouse)
214     {
215       double screenBounds[4];
216       this->GetBounds(screenBounds);
217 
218       labelStartX =
219         static_cast<float>(screenBounds[1] + screenBounds[0]) / 2.0f - labelBounds[1].GetX() / 2.0f;
220       labelStartY = 0;
221     }
222 
223     float scale[2];
224     painter->GetTransform()->GetScale(scale);
225 
226     // Make sure justification is set to left as this is not guaranteed by all
227     // types of vtkChart.
228     vtkTextProperty* currentTextProp = painter->GetTextProp();
229     int currentJustification = currentTextProp->GetJustification();
230     currentTextProp->SetJustificationToLeft();
231     painter->ApplyTextProp(currentTextProp);
232 
233     painter->ApplyBrush(this->RangeLabelBrush);
234     painter->DrawRect(labelStartX - 5.0f / scale[0], labelStartY,
235       labelBounds[1].GetX() + 8.0f / scale[0], labelBounds[1].GetY() + 10.0f / scale[1]);
236     painter->DrawString(labelStartX, labelStartY + 3.0f / scale[1], label.str());
237 
238     // Reset justification
239     currentTextProp->SetJustification(currentJustification);
240     painter->ApplyTextProp(currentTextProp);
241   }
242 
243   this->PaintChildren(painter);
244   return true;
245 }
246 
247 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)248 void vtkPlotRangeHandlesItem::PrintSelf(ostream& os, vtkIndent indent)
249 {
250   this->Superclass::PrintSelf(os, indent);
251 
252   os << indent << "HandleWidth: " << this->HandleWidth << endl;
253   os << indent << "HoveredHandle: " << this->HoveredHandle << endl;
254   os << indent << "ActiveHandle: " << this->ActiveHandle << endl;
255   os << indent << "ActiveHandlePosition: " << this->ActiveHandlePosition << endl;
256   os << indent << "ActiveHandleRangeValue: " << this->ActiveHandleRangeValue << endl;
257 }
258 
259 //------------------------------------------------------------------------------
GetBounds(double * bounds)260 void vtkPlotRangeHandlesItem::GetBounds(double* bounds)
261 {
262   double range[2] = { this->Extent[0], this->Extent[1] };
263   double length[2] = { this->Extent[2], this->Extent[3] };
264 
265   this->GetAxesUnscaledRange(range, length);
266 
267   this->TransformDataToScreen(range[0], length[0], bounds[0], bounds[2]);
268   this->TransformDataToScreen(range[1], length[1], bounds[1], bounds[3]);
269 }
270 
271 //------------------------------------------------------------------------------
GetAxesRange(double * abcissaRange,double * ordinateRange)272 void vtkPlotRangeHandlesItem::GetAxesRange(double* abcissaRange, double* ordinateRange)
273 {
274   // Set default values in case axes are not set
275   if (abcissaRange)
276   {
277     abcissaRange[0] = 0;
278     abcissaRange[1] = 0;
279   }
280 
281   if (ordinateRange)
282   {
283     ordinateRange[0] = 0;
284     ordinateRange[1] = 0;
285   }
286 
287   if (this->HandleOrientation == vtkPlotRangeHandlesItem::VERTICAL)
288   {
289     if (this->GetXAxis())
290     {
291       this->GetXAxis()->GetRange(abcissaRange);
292     }
293 
294     if (this->GetYAxis())
295     {
296       this->GetYAxis()->GetRange(ordinateRange);
297     }
298   }
299   else // HORIZONTAL
300   {
301     if (this->GetYAxis())
302     {
303       this->GetYAxis()->GetRange(abcissaRange);
304     }
305 
306     if (this->GetXAxis())
307     {
308       this->GetXAxis()->GetRange(ordinateRange);
309     }
310   }
311 }
312 
313 //------------------------------------------------------------------------------
GetAxesUnscaledRange(double * abcissaRange,double * ordinateRange)314 void vtkPlotRangeHandlesItem::GetAxesUnscaledRange(double* abcissaRange, double* ordinateRange)
315 {
316   // Set default values in case axes are not set
317   if (abcissaRange)
318   {
319     abcissaRange[0] = 0;
320     abcissaRange[1] = 0;
321   }
322 
323   if (ordinateRange)
324   {
325     ordinateRange[0] = 0;
326     ordinateRange[1] = 0;
327   }
328 
329   if (this->HandleOrientation == vtkPlotRangeHandlesItem::VERTICAL)
330   {
331     if (this->GetXAxis())
332     {
333       this->GetXAxis()->GetUnscaledRange(abcissaRange);
334     }
335 
336     if (this->GetYAxis())
337     {
338       this->GetYAxis()->GetUnscaledRange(ordinateRange);
339     }
340   }
341   else // HORIZONTAL
342   {
343     if (this->GetYAxis())
344     {
345       this->GetYAxis()->GetUnscaledRange(abcissaRange);
346     }
347 
348     if (this->GetXAxis())
349     {
350       this->GetXAxis()->GetUnscaledRange(ordinateRange);
351     }
352   }
353 }
354 
355 //------------------------------------------------------------------------------
TransformScreenToData(const double inX,const double inY,double & outX,double & outY)356 void vtkPlotRangeHandlesItem::TransformScreenToData(
357   const double inX, const double inY, double& outX, double& outY)
358 {
359   if (this->HandleOrientation == vtkPlotRangeHandlesItem::VERTICAL)
360   {
361     this->Superclass::TransformScreenToData(inX, inY, outX, outY);
362   }
363   else
364   {
365     this->Superclass::TransformScreenToData(inY, inX, outY, outX);
366   }
367 }
368 
369 //------------------------------------------------------------------------------
TransformDataToScreen(const double inX,const double inY,double & outX,double & outY)370 void vtkPlotRangeHandlesItem::TransformDataToScreen(
371   const double inX, const double inY, double& outX, double& outY)
372 {
373   if (this->HandleOrientation == vtkPlotRangeHandlesItem::VERTICAL)
374   {
375     this->Superclass::TransformDataToScreen(inX, inY, outX, outY);
376   }
377   else
378   {
379     this->Superclass::TransformDataToScreen(inY, inX, outY, outX);
380   }
381 }
382 
383 //------------------------------------------------------------------------------
Hit(const vtkContextMouseEvent & mouse)384 bool vtkPlotRangeHandlesItem::Hit(const vtkContextMouseEvent& mouse)
385 {
386   if (!this->Interactive || !this->Visible)
387   {
388     return false;
389   }
390 
391   // Add more tolerance than the mouse interaction to make sure handles do
392   // not stay highlighted when moving the mouse
393   vtkVector2f vpos = mouse.GetPos();
394   vtkVector2f tolerance = { 2.0f * this->HandleDelta, 0 };
395   return this->FindRangeHandle(vpos, tolerance) != vtkPlotRangeHandlesItem::NO_HANDLE;
396 }
397 
398 //------------------------------------------------------------------------------
MouseButtonPressEvent(const vtkContextMouseEvent & mouse)399 bool vtkPlotRangeHandlesItem::MouseButtonPressEvent(const vtkContextMouseEvent& mouse)
400 {
401   vtkVector2f vpos = mouse.GetPos();
402   vtkVector2f tolerance = { 2.0f * static_cast<float>(this->HandleDelta), 0 };
403   this->ActiveHandle = this->FindRangeHandle(vpos, tolerance);
404   if (this->ActiveHandle != vtkPlotRangeHandlesItem::NO_HANDLE)
405   {
406     this->HoveredHandle = this->ActiveHandle;
407     this->SetActiveHandlePosition(vpos[this->HandleOrientation]);
408     this->SetCursor(VTK_CURSOR_SIZEWE - this->HandleOrientation);
409     this->GetScene()->SetDirty(true);
410     this->InvokeEvent(vtkCommand::StartInteractionEvent);
411     return true;
412   }
413   return false;
414 }
415 
416 //------------------------------------------------------------------------------
MouseButtonReleaseEvent(const vtkContextMouseEvent & mouse)417 bool vtkPlotRangeHandlesItem::MouseButtonReleaseEvent(const vtkContextMouseEvent& mouse)
418 {
419   if (this->ActiveHandle != vtkPlotRangeHandlesItem::NO_HANDLE)
420   {
421     vtkVector2f vpos = mouse.GetPos();
422     this->SetActiveHandlePosition(vpos[this->HandleOrientation]);
423 
424     if (this->IsActiveHandleMoved(3.0 * this->HandleDelta))
425     {
426       this->HoveredHandle = vtkPlotRangeHandlesItem::NO_HANDLE;
427     }
428     if (this->HoveredHandle == vtkPlotRangeHandlesItem::NO_HANDLE)
429     {
430       this->SetCursor(VTK_CURSOR_SIZEWE - this->HandleOrientation);
431     }
432     this->InvokeEvent(vtkCommand::EndInteractionEvent);
433     this->ActiveHandle = vtkPlotRangeHandlesItem::NO_HANDLE;
434     this->GetScene()->SetDirty(true);
435     return true;
436   }
437   return false;
438 }
439 
440 //------------------------------------------------------------------------------
MouseMoveEvent(const vtkContextMouseEvent & mouse)441 bool vtkPlotRangeHandlesItem::MouseMoveEvent(const vtkContextMouseEvent& mouse)
442 {
443   if (this->ActiveHandle != vtkPlotRangeHandlesItem::NO_HANDLE)
444   {
445     vtkVector2f vpos = mouse.GetPos();
446     this->SetActiveHandlePosition(vpos[this->HandleOrientation]);
447     this->HoveredPosition[this->HandleOrientation] = this->ActiveHandlePosition;
448     this->InvokeEvent(vtkCommand::InteractionEvent);
449     this->GetScene()->SetDirty(true);
450     return true;
451   }
452   return false;
453 }
454 
455 //------------------------------------------------------------------------------
MouseEnterEvent(const vtkContextMouseEvent & mouse)456 bool vtkPlotRangeHandlesItem::MouseEnterEvent(const vtkContextMouseEvent& mouse)
457 {
458   vtkVector2f vpos = mouse.GetPos();
459   vtkVector2f tolerance = { 2.0f * this->HandleDelta, 0 };
460   this->HoveredHandle = this->FindRangeHandle(vpos, tolerance);
461   if (this->HoveredHandle == vtkPlotRangeHandlesItem::NO_HANDLE)
462   {
463     return false;
464   }
465   this->SetCursor(VTK_CURSOR_SIZEWE - this->HandleOrientation);
466   this->GetScene()->SetDirty(true);
467 
468   if (this->ActiveHandle == vtkPlotRangeHandlesItem::NO_HANDLE)
469   {
470     this->HoveredPosition[this->HandleOrientation] = vpos[this->HandleOrientation];
471     this->HoveredPosition[1 - this->HandleOrientation] = vpos[1 - this->HandleOrientation];
472   }
473 
474   return true;
475 }
476 
477 //------------------------------------------------------------------------------
MouseLeaveEvent(const vtkContextMouseEvent & vtkNotUsed (mouse))478 bool vtkPlotRangeHandlesItem::MouseLeaveEvent(const vtkContextMouseEvent& vtkNotUsed(mouse))
479 {
480   if (this->HoveredHandle == vtkPlotRangeHandlesItem::NO_HANDLE)
481   {
482     return false;
483   }
484 
485   this->HoveredHandle = vtkPlotRangeHandlesItem::NO_HANDLE;
486   this->GetScene()->SetDirty(true);
487 
488   if (this->ActiveHandle == vtkPlotRangeHandlesItem::NO_HANDLE)
489   {
490     this->SetCursor(VTK_CURSOR_DEFAULT);
491   }
492 
493   return true;
494 }
495 
496 //------------------------------------------------------------------------------
MouseDoubleClickEvent(const vtkContextMouseEvent & mouse)497 bool vtkPlotRangeHandlesItem::MouseDoubleClickEvent(const vtkContextMouseEvent& mouse)
498 {
499   if (mouse.GetButton() == vtkContextMouseEvent::LEFT_BUTTON)
500   {
501     this->HoveredHandle = vtkPlotRangeHandlesItem::NO_HANDLE;
502     this->InvokeEvent(vtkCommand::LeftButtonDoubleClickEvent);
503     this->GetScene()->SetDirty(true);
504     return true;
505   }
506   return false;
507 }
508 
509 //------------------------------------------------------------------------------
FindRangeHandle(const vtkVector2f & point,const vtkVector2f & tolerance)510 int vtkPlotRangeHandlesItem::FindRangeHandle(const vtkVector2f& point, const vtkVector2f& tolerance)
511 {
512   double pos[2];
513   pos[0] = point.GetX();
514   pos[1] = point.GetY();
515 
516   double length[2] = { this->Extent[2], this->Extent[3] };
517   if (this->ExtentToAxisRange)
518   {
519     double screenBounds[4];
520     this->GetBounds(screenBounds);
521     length[0] = screenBounds[2];
522     length[1] = screenBounds[3];
523   }
524 
525   if (length[0] - tolerance.GetY() <= pos[1 - this->HandleOrientation] &&
526     pos[1 - this->HandleOrientation] <= length[1] + tolerance.GetY())
527   {
528     if (this->LeftHandleDrawRange[0] - tolerance.GetX() <= pos[this->HandleOrientation] &&
529       pos[this->HandleOrientation] <= this->LeftHandleDrawRange[1] + tolerance.GetX())
530     {
531       return vtkPlotRangeHandlesItem::LEFT_HANDLE;
532     }
533     else if (this->RightHandleDrawRange[0] - tolerance.GetX() <= pos[this->HandleOrientation] &&
534       pos[this->HandleOrientation] <= this->RightHandleDrawRange[1] + tolerance.GetX())
535     {
536       return vtkPlotRangeHandlesItem::RIGHT_HANDLE;
537     }
538   }
539   return vtkPlotRangeHandlesItem::NO_HANDLE;
540 }
541 
542 //------------------------------------------------------------------------------
GetHandlesRange(double range[2])543 void vtkPlotRangeHandlesItem::GetHandlesRange(double range[2])
544 {
545   if (this->ActiveHandle != vtkPlotRangeHandlesItem::NO_HANDLE)
546   {
547     double previousExtent = this->Extent[this->ActiveHandle];
548     this->Extent[this->ActiveHandle] = this->ActiveHandleRangeValue;
549     if (this->SynchronizeRangeHandles && this->ActiveHandle == vtkPlotRangeHandlesItem::LEFT_HANDLE)
550     {
551       double shift = this->ActiveHandleRangeValue - previousExtent;
552       this->Extent[1] += shift;
553     }
554   }
555   range[0] = this->Extent[0];
556   range[1] = this->Extent[1];
557 }
558 
559 //------------------------------------------------------------------------------
SetActiveHandlePosition(double position)560 void vtkPlotRangeHandlesItem::SetActiveHandlePosition(double position)
561 {
562   if (this->ActiveHandle != vtkPlotRangeHandlesItem::NO_HANDLE)
563   {
564     // Clamp the position and set the handle position
565     double bounds[4];
566     double clampedPos[2] = { position, 1 };
567     this->GetBounds(bounds);
568 
569     double minRange = bounds[0];
570     double maxRange = bounds[1];
571     bounds[0] += this->HandleDelta;
572     bounds[1] -= this->HandleDelta;
573 
574     vtkPlot::ClampPos(clampedPos, bounds);
575 
576     this->ActiveHandlePosition = clampedPos[0];
577 
578     // Correct the position for range set
579     if (this->ActiveHandle == vtkPlotRangeHandlesItem::LEFT_HANDLE)
580     {
581       position -= this->HandleDelta;
582     }
583     else // if (this->ActiveHandle == vtkPlotRangeHandlesItem::RIGHT_HANDLE)
584     {
585       position += this->HandleDelta;
586     }
587 
588     // Make the range value stick to the range for easier use
589     if (minRange - this->HandleDelta <= clampedPos[0] &&
590       clampedPos[0] <= minRange + this->HandleDelta)
591     {
592       position = minRange;
593     }
594     if (maxRange - this->HandleDelta <= clampedPos[0] &&
595       clampedPos[0] <= maxRange + this->HandleDelta)
596     {
597       position = maxRange;
598     }
599 
600     // Transform it to data and set it
601     double unused;
602     this->TransformScreenToData(position, 1, this->ActiveHandleRangeValue, unused);
603   }
604 }
605 
606 //------------------------------------------------------------------------------
IsActiveHandleMoved(double tolerance)607 bool vtkPlotRangeHandlesItem::IsActiveHandleMoved(double tolerance)
608 {
609   if (this->ActiveHandle == vtkPlotRangeHandlesItem::NO_HANDLE)
610   {
611     return false;
612   }
613 
614   double unused, position;
615   this->TransformDataToScreen(this->ActiveHandleRangeValue, 1, position, unused);
616 
617   double bounds[4];
618   this->GetBounds(bounds);
619 
620   return (bounds[this->ActiveHandle] - tolerance <= position &&
621     position <= bounds[this->ActiveHandle] + tolerance);
622 }
623 
624 //------------------------------------------------------------------------------
SetCursor(int cursor)625 void vtkPlotRangeHandlesItem::SetCursor(int cursor)
626 {
627   vtkRenderer* renderer = this->GetScene()->GetRenderer();
628   if (renderer)
629   {
630     vtkRenderWindow* window = renderer->GetRenderWindow();
631     if (window)
632     {
633       window->SetCurrentCursor(cursor);
634     }
635   }
636 }
637