Mercurial > hg > orthanc-stone
comparison Framework/Widgets/WorldSceneWidget.cpp @ 281:300d8b8c48b3 am-2
mouse tracker tuning
author | am@osimis.io |
---|---|
date | Tue, 28 Aug 2018 10:01:31 +0200 |
parents | 8a86695fcbc3 |
children | 8bdc6112bc2e |
comparison
equal
deleted
inserted
replaced
280:829163c6efc1 | 281:300d8b8c48b3 |
---|---|
11 * | 11 * |
12 * This program is distributed in the hope that it will be useful, but | 12 * This program is distributed in the hope that it will be useful, but |
13 * WITHOUT ANY WARRANTY; without even the implied warranty of | 13 * WITHOUT ANY WARRANTY; without even the implied warranty of |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 * Affero General Public License for more details. | 15 * Affero General Public License for more details. |
16 * | 16 * |
17 * You should have received a copy of the GNU Affero General Public License | 17 * You should have received a copy of the GNU Affero General Public License |
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 **/ | 19 **/ |
20 | 20 |
21 | 21 |
57 observer.NotifySizeChange(source, view_); | 57 observer.NotifySizeChange(source, view_); |
58 } | 58 } |
59 }; | 59 }; |
60 | 60 |
61 | 61 |
62 // this is an adapter between a IWorldSceneMouseTracker | |
63 // that is tracking a mouse in scene coordinates/mm and | |
64 // an IMouseTracker that is tracking a mouse | |
65 // in screen coordinates/pixels. | |
62 class WorldSceneWidget::SceneMouseTracker : public IMouseTracker | 66 class WorldSceneWidget::SceneMouseTracker : public IMouseTracker |
63 { | 67 { |
64 private: | 68 private: |
65 ViewportGeometry view_; | 69 ViewportGeometry view_; |
66 std::auto_ptr<IWorldSceneMouseTracker> tracker_; | 70 std::auto_ptr<IWorldSceneMouseTracker> tracker_; |
67 | 71 |
68 public: | 72 public: |
69 SceneMouseTracker(const ViewportGeometry& view, | 73 SceneMouseTracker(const ViewportGeometry& view, |
70 IWorldSceneMouseTracker* tracker) : | 74 IWorldSceneMouseTracker* tracker) : |
71 view_(view), | 75 view_(view), |
72 tracker_(tracker) | 76 tracker_(tracker) |
75 } | 79 } |
76 | 80 |
77 virtual void Render(Orthanc::ImageAccessor& target) | 81 virtual void Render(Orthanc::ImageAccessor& target) |
78 { | 82 { |
79 CairoSurface surface(target); | 83 CairoSurface surface(target); |
80 CairoContext context(surface); | 84 CairoContext context(surface); |
81 view_.ApplyTransform(context); | 85 view_.ApplyTransform(context); |
82 tracker_->Render(context, view_.GetZoom()); | 86 tracker_->Render(context, view_.GetZoom()); |
83 } | 87 } |
84 | 88 |
85 virtual void MouseUp() | 89 virtual void MouseUp() |
86 { | 90 { |
87 tracker_->MouseUp(); | 91 tracker_->MouseUp(); |
88 } | 92 } |
89 | 93 |
90 virtual void MouseMove(int x, | 94 virtual void MouseMove(int x, |
91 int y) | 95 int y) |
92 { | 96 { |
93 double sceneX, sceneY; | 97 double sceneX, sceneY; |
94 MapMouseToScene(sceneX, sceneY, view_, x, y); | 98 MapMouseToScene(sceneX, sceneY, view_, x, y); |
95 tracker_->MouseMove(sceneX, sceneY); | 99 tracker_->MouseMove(sceneX, sceneY); |
96 } | 100 } |
97 }; | 101 }; |
98 | 102 |
99 | 103 |
100 class WorldSceneWidget::PanMouseTracker : public IMouseTracker | 104 WorldSceneWidget::PanMouseTracker::PanMouseTracker(WorldSceneWidget& that, |
101 { | 105 int x, |
102 private: | 106 int y) : |
103 WorldSceneWidget& that_; | 107 that_(that), |
104 double previousPanX_; | 108 downX_(x), |
105 double previousPanY_; | 109 downY_(y) |
106 double downX_; | 110 { |
107 double downY_; | 111 that_.view_.GetPan(previousPanX_, previousPanY_); |
108 | 112 } |
109 public: | 113 |
110 PanMouseTracker(WorldSceneWidget& that, | 114 void WorldSceneWidget::PanMouseTracker::MouseMove(int x, int y) |
111 int x, | 115 { |
112 int y) : | 116 that_.view_.SetPan(previousPanX_ + x - downX_, |
113 that_(that), | 117 previousPanY_ + y - downY_); |
114 downX_(x), | 118 |
115 downY_(y) | 119 that_.observers_.Apply(that_, &IWorldObserver::NotifyViewChange, that_.view_); |
116 { | 120 } |
117 that_.view_.GetPan(previousPanX_, previousPanY_); | 121 |
118 } | 122 WorldSceneWidget::ZoomMouseTracker::ZoomMouseTracker(WorldSceneWidget& that, |
119 | 123 int x, |
120 virtual void Render(Orthanc::ImageAccessor& surface) | 124 int y) : |
121 { | 125 that_(that), |
122 } | 126 downX_(x), |
123 | 127 downY_(y) |
124 virtual void MouseUp() | 128 { |
125 { | 129 oldZoom_ = that_.view_.GetZoom(); |
126 } | 130 MapMouseToScene(centerX_, centerY_, that_.view_, downX_, downY_); |
127 | 131 } |
128 virtual void MouseMove(int x, | 132 |
129 int y) | 133 void WorldSceneWidget::ZoomMouseTracker::MouseMove(int x, |
130 { | 134 int y) |
131 that_.view_.SetPan(previousPanX_ + x - downX_, | 135 { |
132 previousPanY_ + y - downY_); | 136 static const double MIN_ZOOM = -4; |
133 | 137 static const double MAX_ZOOM = 4; |
134 that_.observers_.Apply(that_, &IWorldObserver::NotifyViewChange, that_.view_); | 138 |
135 } | 139 if (that_.view_.GetDisplayHeight() <= 3) |
136 }; | 140 { |
137 | 141 return; // Cannot zoom on such a small image |
138 | 142 } |
139 class WorldSceneWidget::ZoomMouseTracker : public IMouseTracker | 143 |
140 { | 144 double dy = (static_cast<double>(y - downY_) / |
141 private: | 145 static_cast<double>(that_.view_.GetDisplayHeight() - 1)); // In the range [-1,1] |
142 WorldSceneWidget& that_; | 146 double z; |
143 int downX_; | 147 |
144 int downY_; | 148 // Linear interpolation from [-1, 1] to [MIN_ZOOM, MAX_ZOOM] |
145 double centerX_; | 149 if (dy < -1.0) |
146 double centerY_; | 150 { |
147 double oldZoom_; | 151 z = MIN_ZOOM; |
148 | 152 } |
149 public: | 153 else if (dy > 1.0) |
150 ZoomMouseTracker(WorldSceneWidget& that, | 154 { |
151 int x, | 155 z = MAX_ZOOM; |
152 int y) : | 156 } |
153 that_(that), | 157 else |
154 downX_(x), | 158 { |
155 downY_(y) | 159 z = MIN_ZOOM + (MAX_ZOOM - MIN_ZOOM) * (dy + 1.0) / 2.0; |
156 { | 160 } |
157 oldZoom_ = that_.view_.GetZoom(); | 161 |
158 MapMouseToScene(centerX_, centerY_, that_.view_, downX_, downY_); | 162 z = pow(2.0, z); |
159 } | 163 |
160 | 164 that_.view_.SetZoom(oldZoom_ * z); |
161 virtual void Render(Orthanc::ImageAccessor& surface) | 165 |
162 { | 166 // Correct the pan so that the original click point is kept at |
163 } | 167 // the same location on the display |
164 | 168 double panX, panY; |
165 virtual void MouseUp() | 169 that_.view_.GetPan(panX, panY); |
166 { | 170 |
167 } | 171 int tx, ty; |
168 | 172 that_.view_.MapSceneToDisplay(tx, ty, centerX_, centerY_); |
169 virtual void MouseMove(int x, | 173 that_.view_.SetPan(panX + static_cast<double>(downX_ - tx), |
170 int y) | 174 panY + static_cast<double>(downY_ - ty)); |
171 { | 175 |
172 static const double MIN_ZOOM = -4; | 176 that_.observers_.Apply(that_, &IWorldObserver::NotifyViewChange, that_.view_); |
173 static const double MAX_ZOOM = 4; | 177 } |
174 | |
175 if (that_.view_.GetDisplayHeight() <= 3) | |
176 { | |
177 return; // Cannot zoom on such a small image | |
178 } | |
179 | |
180 double dy = (static_cast<double>(y - downY_) / | |
181 static_cast<double>(that_.view_.GetDisplayHeight() - 1)); // In the range [-1,1] | |
182 double z; | |
183 | |
184 // Linear interpolation from [-1, 1] to [MIN_ZOOM, MAX_ZOOM] | |
185 if (dy < -1.0) | |
186 { | |
187 z = MIN_ZOOM; | |
188 } | |
189 else if (dy > 1.0) | |
190 { | |
191 z = MAX_ZOOM; | |
192 } | |
193 else | |
194 { | |
195 z = MIN_ZOOM + (MAX_ZOOM - MIN_ZOOM) * (dy + 1.0) / 2.0; | |
196 } | |
197 | |
198 z = pow(2.0, z); | |
199 | |
200 that_.view_.SetZoom(oldZoom_ * z); | |
201 | |
202 // Correct the pan so that the original click point is kept at | |
203 // the same location on the display | |
204 double panX, panY; | |
205 that_.view_.GetPan(panX, panY); | |
206 | |
207 int tx, ty; | |
208 that_.view_.MapSceneToDisplay(tx, ty, centerX_, centerY_); | |
209 that_.view_.SetPan(panX + static_cast<double>(downX_ - tx), | |
210 panY + static_cast<double>(downY_ - ty)); | |
211 | |
212 that_.observers_.Apply(that_, &IWorldObserver::NotifyViewChange, that_.view_); | |
213 } | |
214 }; | |
215 | 178 |
216 | 179 |
217 bool WorldSceneWidget::RenderCairo(CairoContext& context) | 180 bool WorldSceneWidget::RenderCairo(CairoContext& context) |
218 { | 181 { |
219 view_.ApplyTransform(context); | 182 view_.ApplyTransform(context); |
300 KeyboardModifiers modifiers) | 263 KeyboardModifiers modifiers) |
301 { | 264 { |
302 double sceneX, sceneY; | 265 double sceneX, sceneY; |
303 MapMouseToScene(sceneX, sceneY, view_, x, y); | 266 MapMouseToScene(sceneX, sceneY, view_, x, y); |
304 | 267 |
268 // asks the Widget Interactor to provide a mouse tracker | |
305 std::auto_ptr<IWorldSceneMouseTracker> tracker | 269 std::auto_ptr<IWorldSceneMouseTracker> tracker |
306 (CreateMouseSceneTracker(view_, button, sceneX, sceneY, modifiers)); | 270 (CreateMouseSceneTracker(view_, button, sceneX, sceneY, modifiers)); |
307 | 271 |
308 if (tracker.get() != NULL) | 272 if (tracker.get() != NULL) |
309 { | 273 { |
310 return new SceneMouseTracker(view_, tracker.release()); | 274 return new SceneMouseTracker(view_, tracker.release()); |
311 } | 275 } |
312 | 276 //TODO: allow Interactor to create Pan & Zoom |
313 switch (button) | 277 switch (button) |
314 { | 278 { |
315 case MouseButton_Middle: | 279 case MouseButton_Middle: |
316 return new PanMouseTracker(*this, x, y); | 280 return new PanMouseTracker(*this, x, y); |
317 | 281 |
318 case MouseButton_Right: | 282 case MouseButton_Right: |
319 return new ZoomMouseTracker(*this, x, y); | 283 return new ZoomMouseTracker(*this, x, y); |
320 | 284 |
321 default: | 285 default: |
322 return NULL; | 286 return NULL; |
323 } | 287 } |
324 } | 288 } |
325 | 289 |
326 | 290 |
327 void WorldSceneWidget::RenderSceneMouseOver(CairoContext& context, | 291 void WorldSceneWidget::RenderSceneMouseOver(CairoContext& context, |
341 double y, | 305 double y, |
342 KeyboardModifiers modifiers) | 306 KeyboardModifiers modifiers) |
343 { | 307 { |
344 if (interactor_) | 308 if (interactor_) |
345 { | 309 { |
346 return interactor_->CreateMouseTracker(*this, view, button, x, y, GetStatusBar()); | 310 return interactor_->CreateMouseTracker(*this, view, button, modifiers, x, y, GetStatusBar()); |
347 } | 311 } |
348 else | 312 else |
349 { | 313 { |
350 return NULL; | 314 return NULL; |
351 } | 315 } |
353 | 317 |
354 | 318 |
355 void WorldSceneWidget::MouseWheel(MouseWheelDirection direction, | 319 void WorldSceneWidget::MouseWheel(MouseWheelDirection direction, |
356 int x, | 320 int x, |
357 int y, | 321 int y, |
358 KeyboardModifiers modifiers) | 322 KeyboardModifiers modifiers) |
359 { | 323 { |
360 if (interactor_) | 324 if (interactor_) |
361 { | 325 { |
362 interactor_->MouseWheel(*this, direction, modifiers, GetStatusBar()); | 326 interactor_->MouseWheel(*this, direction, modifiers, GetStatusBar()); |
363 } | 327 } |