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 }