1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkPlotRangeHandlesItem.h
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 /**
17  * @class   vtkPlotRangeHandlesItem
18  * @brief   item to show and control a range on vtkAxis
19  *
20  * vtkPlotRangeHandlesItem provides range handles painting and management
21  * for a provided extent.
22  * Handles can be moved by clicking on them.
23  * The range is shown when hovering or moving the handles.
24  * It emits a StartInteractionEvent when starting to interact with a handle,
25  * an InteractionEvent when interacting with a handle and an EndInteractionEvent
26  * when releasing a handle.
27  * It emits a LeftMouseButtonDoubleClickEvent when double clicked.
28  * Options can be used to change the appearence or behavior of handles:
29  * - SynchronizeHandlesRange: When enabled, moving the minimum handle triggers
30  * the modification of the whole range, resulting in the maximum handle being
31  * moved too. Disabled by default.
32  * - Orientation: Choose between horizontal (Y axis) or vertical (X axis)
33  * handles. Default is vertical.
34  * - ExtentToAxis: When enabled, the height of handles span the range of the
35  * opposite axis. If disabled, the height of handles is defined by the provided
36  * extent. Enabled by default.
37  */
38 
39 #ifndef vtkPlotRangeHandlesItem_h
40 #define vtkPlotRangeHandlesItem_h
41 
42 #include "vtkChartsCoreModule.h" // For export macro
43 #include "vtkCommand.h"          // For vtkCommand enum
44 #include "vtkPlot.h"
45 
46 class vtkBrush;
47 
48 class VTKCHARTSCORE_EXPORT vtkPlotRangeHandlesItem : public vtkPlot
49 {
50 public:
51   vtkTypeMacro(vtkPlotRangeHandlesItem, vtkPlot);
52   void PrintSelf(ostream& os, vtkIndent indent) override;
53   static vtkPlotRangeHandlesItem* New();
54 
55   enum Handle
56   {
57     NO_HANDLE = -1,
58     LEFT_HANDLE = 0,
59     RIGHT_HANDLE = 1
60   };
61 
62   enum Orientation
63   {
64     VERTICAL = 0,
65     HORIZONTAL = 1
66   };
67 
68   /**
69    * Paint both handles and the range if
70    * a handle is active or hovered
71    */
72   bool Paint(vtkContext2D* painter) override;
73 
74   /**
75    * Recover the bounds of the item
76    */
77   void GetBounds(double bounds[4]) override;
78 
79   /**
80    * Recover the range currently set by the handles
81    * Use this method by observing EndInteractionEvent
82    */
83   virtual void GetHandlesRange(double range[2]);
84 
85   ///@{
86   /**
87    * Set/Get the handles width in pixels.
88    * Default is 2.
89    */
90   vtkSetMacro(HandleWidth, float);
91   vtkGetMacro(HandleWidth, float);
92   ///@}
93 
94   ///@{
95   /**
96    * Set/Get the handles orientation in the plot.
97    */
98   vtkSetClampMacro(HandleOrientation, int, VERTICAL, HORIZONTAL);
99   vtkGetMacro(HandleOrientation, int);
SetHandleOrientationToVertical()100   void SetHandleOrientationToVertical() { this->SetHandleOrientation(VERTICAL); }
SetHandleOrientationToHorizontal()101   void SetHandleOrientationToHorizontal() { this->SetHandleOrientation(HORIZONTAL); }
102   ///@}
103 
104   ///@{
105   /**
106    * Set/Get the extent of the handles in data space (axis unscaled range).
107    * The first two parameters define the left and right handles positions on
108    * the axis. The last two parameters define the length of handles along the
109    * opposite axis. Default values are set to (0, 1, 0, 1).
110    * When using ExtentToAxisRangeOn(), the last two parameters don't have any
111    * effect and handles span the axis range.
112    */
113   vtkSetVector4Macro(Extent, double);
114   vtkGetVector4Macro(Extent, double);
115   ///@}
116 
117   ///@{
118   /**
119    * Set/Get whether handles span the range of the axis. Default is On.
120    */
121   vtkSetMacro(ExtentToAxisRange, vtkTypeBool);
122   vtkGetMacro(ExtentToAxisRange, vtkTypeBool);
123   vtkBooleanMacro(ExtentToAxisRange, vtkTypeBool);
124   ///@}
125 
126   ///@{
127   /**
128    * Set/Get whether handles move together when one of them is update. Default is Off.
129    */
130   vtkSetMacro(SynchronizeRangeHandles, vtkTypeBool);
131   vtkGetMacro(SynchronizeRangeHandles, vtkTypeBool);
132   vtkBooleanMacro(SynchronizeRangeHandles, vtkTypeBool);
133   ///@}
134 
135   ///@{
136   /**
137    * If On, the range tooltip is always rendered using mouse position,
138    * otherwise it is placed at the center of the x axis Default is On.
139    */
140   vtkSetMacro(LockTooltipToMouse, vtkTypeBool);
141   vtkGetMacro(LockTooltipToMouse, vtkTypeBool);
142   vtkBooleanMacro(LockTooltipToMouse, vtkTypeBool);
143   ///@}
144 
145   /**
146    * Return the brush used to paint handles being hovered
147    */
148   vtkGetObjectMacro(HighlightBrush, vtkBrush);
149 
150   /**
151    * Compute the handles draw range by using the handle width and the transfer function
152    */
153   virtual void ComputeHandlesDrawRange();
154 
155 protected:
156   vtkPlotRangeHandlesItem();
157   ~vtkPlotRangeHandlesItem() override;
158 
159   ///@{
160   /**
161    * Get the logical range of abcissa or ordinate axis based on the handle
162    * orientation, in plot coordinates.
163 
164    * The unscaled range will always be in the same coordinate system of
165    * the data being plotted, regardless of whether LogScale is true or false.
166    * Calling GetAxisRange() when LogScale is true will return the log10({min, max}).
167    */
168   void GetAxesRange(double* abcissaRange, double* ordinateRange);
169   void GetAxesUnscaledRange(double* abcissaRange, double* ordinateRange);
170   ///@}
171 
172   /**
173    * Compute the range used for the handles.
174    */
175   void ComputeRange(double* range);
176 
177   /**
178    * Compute the delta used for the picking handle size.
179    */
180   void ComputeHandleDelta(double screenBounds[4]);
181 
182   ///@{
183   /**
184    * Transform the mouse event in the control-points space. This is needed when
185    * using logScale or shiftscale.
186    */
187   using vtkPlot::TransformDataToScreen;
188   using vtkPlot::TransformScreenToData;
189   void TransformScreenToData(
190     const double inX, const double inY, double& outX, double& outY) override;
191   void TransformDataToScreen(
192     const double inX, const double inY, double& outX, double& outY) override;
193   ///@}
194 
195   /**
196    * Returns true if the supplied x, y coordinate is around a handle
197    */
198   bool Hit(const vtkContextMouseEvent& mouse) override;
199 
200   ///@{
201   /**
202    * Interaction methods to interact with the handles.
203    */
204   bool MouseButtonPressEvent(const vtkContextMouseEvent& mouse) override;
205   bool MouseButtonReleaseEvent(const vtkContextMouseEvent& mouse) override;
206   bool MouseMoveEvent(const vtkContextMouseEvent& mouse) override;
207   bool MouseEnterEvent(const vtkContextMouseEvent& mouse) override;
208   bool MouseLeaveEvent(const vtkContextMouseEvent& mouse) override;
209   bool MouseDoubleClickEvent(const vtkContextMouseEvent& mouse) override;
210   ///@}
211 
212   /**
213    * Returns the handle the provided point is over with a provided tolerance,
214    * it can be NO_HANDLE, LEFT_HANDLE or RIGHT_HANDLE
215    */
216   virtual int FindRangeHandle(const vtkVector2f& point, const vtkVector2f& tolerance);
217 
218   /**
219    * Internal method to set the ActiveHandlePosition
220    * and compute the ActiveHandleRangeValue accordingly
221    */
222   virtual void SetActiveHandlePosition(double position);
223 
224   /**
225    * Internal method to check if the active handle have
226    * actually been moved.
227    */
228   bool IsActiveHandleMoved(double tolerance);
229 
230   /**
231    * Set the cursor shape
232    */
233   void SetCursor(int cursor);
234 
235   vtkPlotRangeHandlesItem(const vtkPlotRangeHandlesItem&) = delete;
236   void operator=(const vtkPlotRangeHandlesItem&) = delete;
237 
238   float HandleWidth = 2;
239   float HandleDelta = 0;
240   float LeftHandleDrawRange[2] = { 0, 0 };
241   float RightHandleDrawRange[2] = { 0, 0 };
242   int ActiveHandle = NO_HANDLE;
243   int HoveredHandle = NO_HANDLE;
244   float HoveredPosition[2] = { 0, 0 };
245   vtkTypeBool LockTooltipToMouse = true;
246   double ActiveHandlePosition = 0;
247   double ActiveHandleRangeValue = 0;
248   vtkNew<vtkBrush> HighlightBrush;
249   vtkNew<vtkBrush> RangeLabelBrush;
250   double Extent[4] = { 0, 1, 0, 1 };
251   vtkTypeBool ExtentToAxisRange = true;
252   vtkTypeBool SynchronizeRangeHandles = false;
253   int HandleOrientation = VERTICAL;
254 };
255 
256 #endif // vtkPlotRangeHandlesItem_h
257