Mercurial > hg > orthanc-stone
annotate Framework/Widgets/WorldSceneWidget.cpp @ 93:5945e81734a3 wasm
decoding of JPEG images
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 29 May 2017 17:28:31 +0200 |
parents | 81f73efd81a1 |
children | 53bd9277b025 |
rev | line source |
---|---|
0 | 1 /** |
2 * Stone of Orthanc | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
40
7207a407bcd8
shared copyright with osimis
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
5 * Copyright (C) 2017 Osimis, Belgium |
0 | 6 * |
7 * This program is free software: you can redistribute it and/or | |
47 | 8 * modify it under the terms of the GNU Affero General Public License |
9 * as published by the Free Software Foundation, either version 3 of | |
10 * the License, or (at your option) any later version. | |
0 | 11 * |
12 * This program is distributed in the hope that it will be useful, but | |
13 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
47 | 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 * Affero General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Affero General Public License | |
0 | 18 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 **/ | |
20 | |
21 | |
22 #include "WorldSceneWidget.h" | |
23 | |
24 namespace OrthancStone | |
25 { | |
26 static void MapMouseToScene(double& sceneX, | |
27 double& sceneY, | |
28 const ViewportGeometry& view, | |
29 int mouseX, | |
30 int mouseY) | |
31 { | |
32 // Take the center of the pixel | |
33 double x, y; | |
34 x = static_cast<double>(mouseX) + 0.5; | |
35 y = static_cast<double>(mouseY) + 0.5; | |
36 | |
37 view.MapDisplayToScene(sceneX, sceneY, x, y); | |
38 } | |
39 | |
40 | |
41 struct WorldSceneWidget::SizeChangeFunctor | |
42 { | |
43 ViewportGeometry& view_; | |
44 | |
45 SizeChangeFunctor(ViewportGeometry& view) : | |
46 view_(view) | |
47 { | |
48 } | |
49 | |
50 void operator() (IWorldObserver& observer, | |
51 const WorldSceneWidget& source) | |
52 { | |
53 observer.NotifySizeChange(source, view_); | |
54 } | |
55 }; | |
56 | |
57 | |
58 class WorldSceneWidget::SceneMouseTracker : public IMouseTracker | |
59 { | |
60 private: | |
61 ViewportGeometry view_; | |
62 std::auto_ptr<IWorldSceneMouseTracker> tracker_; | |
63 | |
64 public: | |
65 SceneMouseTracker(const ViewportGeometry& view, | |
66 IWorldSceneMouseTracker* tracker) : | |
67 view_(view), | |
68 tracker_(tracker) | |
69 { | |
70 assert(tracker != NULL); | |
71 } | |
72 | |
73 virtual void Render(Orthanc::ImageAccessor& target) | |
74 { | |
75 CairoSurface surface(target); | |
76 CairoContext context(surface); | |
77 view_.ApplyTransform(context); | |
78 tracker_->Render(context, view_.GetZoom()); | |
79 } | |
80 | |
81 virtual void MouseUp() | |
82 { | |
83 tracker_->MouseUp(); | |
84 } | |
85 | |
86 virtual void MouseMove(int x, | |
87 int y) | |
88 { | |
89 double sceneX, sceneY; | |
90 MapMouseToScene(sceneX, sceneY, view_, x, y); | |
91 tracker_->MouseMove(sceneX, sceneY); | |
92 } | |
93 }; | |
94 | |
95 | |
96 class WorldSceneWidget::PanMouseTracker : public IMouseTracker | |
97 { | |
98 private: | |
99 WorldSceneWidget& that_; | |
100 double previousPanX_; | |
101 double previousPanY_; | |
102 double downX_; | |
103 double downY_; | |
104 | |
105 public: | |
106 PanMouseTracker(WorldSceneWidget& that, | |
107 int x, | |
108 int y) : | |
109 that_(that), | |
110 downX_(x), | |
111 downY_(y) | |
112 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
113 that_.view_.GetPan(previousPanX_, previousPanY_); |
0 | 114 } |
115 | |
116 virtual void Render(Orthanc::ImageAccessor& surface) | |
117 { | |
118 } | |
119 | |
120 virtual void MouseUp() | |
121 { | |
122 } | |
123 | |
124 virtual void MouseMove(int x, | |
125 int y) | |
126 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
127 that_.view_.SetPan(previousPanX_ + x - downX_, |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
128 previousPanY_ + y - downY_); |
0 | 129 |
91 | 130 that_.observers_.Apply(that_, &IWorldObserver::NotifyViewChange, that_.view_); |
0 | 131 } |
132 }; | |
133 | |
134 | |
135 class WorldSceneWidget::ZoomMouseTracker : public IMouseTracker | |
136 { | |
137 private: | |
138 WorldSceneWidget& that_; | |
139 int downX_; | |
140 int downY_; | |
141 double centerX_; | |
142 double centerY_; | |
143 double oldZoom_; | |
144 | |
145 public: | |
146 ZoomMouseTracker(WorldSceneWidget& that, | |
147 int x, | |
148 int y) : | |
149 that_(that), | |
150 downX_(x), | |
151 downY_(y) | |
152 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
153 oldZoom_ = that_.view_.GetZoom(); |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
154 MapMouseToScene(centerX_, centerY_, that_.view_, downX_, downY_); |
0 | 155 } |
156 | |
157 virtual void Render(Orthanc::ImageAccessor& surface) | |
158 { | |
159 } | |
160 | |
161 virtual void MouseUp() | |
162 { | |
163 } | |
164 | |
165 virtual void MouseMove(int x, | |
166 int y) | |
167 { | |
168 static const double MIN_ZOOM = -4; | |
169 static const double MAX_ZOOM = 4; | |
170 | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
171 if (that_.view_.GetDisplayHeight() <= 3) |
0 | 172 { |
173 return; // Cannot zoom on such a small image | |
174 } | |
175 | |
176 double dy = (static_cast<double>(y - downY_) / | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
177 static_cast<double>(that_.view_.GetDisplayHeight() - 1)); // In the range [-1,1] |
0 | 178 double z; |
179 | |
180 // Linear interpolation from [-1, 1] to [MIN_ZOOM, MAX_ZOOM] | |
181 if (dy < -1.0) | |
182 { | |
183 z = MIN_ZOOM; | |
184 } | |
185 else if (dy > 1.0) | |
186 { | |
187 z = MAX_ZOOM; | |
188 } | |
189 else | |
190 { | |
191 z = MIN_ZOOM + (MAX_ZOOM - MIN_ZOOM) * (dy + 1.0) / 2.0; | |
192 } | |
193 | |
194 z = pow(2.0, z); | |
195 | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
196 that_.view_.SetZoom(oldZoom_ * z); |
0 | 197 |
198 // Correct the pan so that the original click point is kept at | |
199 // the same location on the display | |
200 double panX, panY; | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
201 that_.view_.GetPan(panX, panY); |
0 | 202 |
203 int tx, ty; | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
204 that_.view_.MapSceneToDisplay(tx, ty, centerX_, centerY_); |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
205 that_.view_.SetPan(panX + static_cast<double>(downX_ - tx), |
0 | 206 panY + static_cast<double>(downY_ - ty)); |
207 | |
91 | 208 that_.observers_.Apply(that_, &IWorldObserver::NotifyViewChange, that_.view_); |
0 | 209 } |
210 }; | |
211 | |
212 | |
213 bool WorldSceneWidget::RenderCairo(CairoContext& context) | |
214 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
215 view_.ApplyTransform(context); |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
216 return RenderScene(context, view_); |
0 | 217 } |
218 | |
219 | |
220 void WorldSceneWidget::RenderMouseOverCairo(CairoContext& context, | |
221 int x, | |
222 int y) | |
223 { | |
224 ViewportGeometry view = GetView(); | |
225 view.ApplyTransform(context); | |
226 | |
227 double sceneX, sceneY; | |
228 MapMouseToScene(sceneX, sceneY, view, x, y); | |
229 RenderSceneMouseOver(context, view, sceneX, sceneY); | |
230 } | |
231 | |
232 | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
233 void WorldSceneWidget::SetSceneExtent(ViewportGeometry& view) |
0 | 234 { |
235 double x1, y1, x2, y2; | |
236 GetSceneExtent(x1, y1, x2, y2); | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
237 view.SetSceneExtent(x1, y1, x2, y2); |
0 | 238 } |
239 | |
240 | |
241 void WorldSceneWidget::SetSize(unsigned int width, | |
242 unsigned int height) | |
243 { | |
244 CairoWidget::SetSize(width, height); | |
245 | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
246 view_.SetDisplaySize(width, height); |
0 | 247 |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
248 if (observers_.IsEmpty()) |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
249 { |
66 | 250 // Without a size observer, reset to the default view |
251 // view_.SetDefaultView(); | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
252 } |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
253 else |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
254 { |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
255 // With a size observer, let it decide which view to use |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
256 SizeChangeFunctor functor(view_); |
91 | 257 observers_.Notify(*this, functor); |
0 | 258 } |
259 } | |
260 | |
261 | |
262 void WorldSceneWidget::SetInteractor(IWorldSceneInteractor& interactor) | |
263 { | |
264 interactor_ = &interactor; | |
265 } | |
266 | |
267 | |
268 void WorldSceneWidget::SetDefaultView() | |
269 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
270 SetSceneExtent(view_); |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
271 view_.SetDefaultView(); |
0 | 272 |
273 NotifyChange(); | |
274 | |
91 | 275 observers_.Apply(*this, &IWorldObserver::NotifyViewChange, view_); |
0 | 276 } |
277 | |
278 | |
279 void WorldSceneWidget::SetView(const ViewportGeometry& view) | |
280 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
281 view_ = view; |
0 | 282 |
283 NotifyChange(); | |
284 | |
91 | 285 observers_.Apply(*this, &IWorldObserver::NotifyViewChange, view_); |
0 | 286 } |
287 | |
288 | |
289 ViewportGeometry WorldSceneWidget::GetView() | |
290 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
291 return view_; |
0 | 292 } |
293 | |
294 | |
295 IMouseTracker* WorldSceneWidget::CreateMouseTracker(MouseButton button, | |
296 int x, | |
297 int y, | |
298 KeyboardModifiers modifiers) | |
299 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
300 double sceneX, sceneY; |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
301 MapMouseToScene(sceneX, sceneY, view_, x, y); |
0 | 302 |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
303 std::auto_ptr<IWorldSceneMouseTracker> tracker |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
304 (CreateMouseSceneTracker(view_, button, sceneX, sceneY, modifiers)); |
0 | 305 |
306 if (tracker.get() != NULL) | |
307 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
308 return new SceneMouseTracker(view_, tracker.release()); |
0 | 309 } |
310 | |
311 switch (button) | |
312 { | |
313 case MouseButton_Middle: | |
314 return new PanMouseTracker(*this, x, y); | |
315 | |
316 case MouseButton_Right: | |
317 return new ZoomMouseTracker(*this, x, y); | |
318 | |
319 default: | |
320 return NULL; | |
321 } | |
322 } | |
323 | |
324 | |
325 void WorldSceneWidget::RenderSceneMouseOver(CairoContext& context, | |
326 const ViewportGeometry& view, | |
327 double x, | |
328 double y) | |
329 { | |
330 if (interactor_) | |
331 { | |
59 | 332 interactor_->MouseOver(context, *this, view, x, y, GetStatusBar()); |
0 | 333 } |
334 } | |
335 | |
336 IWorldSceneMouseTracker* WorldSceneWidget::CreateMouseSceneTracker(const ViewportGeometry& view, | |
337 MouseButton button, | |
338 double x, | |
339 double y, | |
340 KeyboardModifiers modifiers) | |
341 { | |
342 if (interactor_) | |
343 { | |
59 | 344 return interactor_->CreateMouseTracker(*this, view, button, x, y, GetStatusBar()); |
0 | 345 } |
346 else | |
347 { | |
348 return NULL; | |
349 } | |
350 } | |
351 | |
352 | |
353 void WorldSceneWidget::MouseWheel(MouseWheelDirection direction, | |
354 int x, | |
355 int y, | |
356 KeyboardModifiers modifiers) | |
357 { | |
358 if (interactor_) | |
359 { | |
360 interactor_->MouseWheel(*this, direction, modifiers, GetStatusBar()); | |
361 } | |
362 } | |
363 | |
364 | |
365 void WorldSceneWidget::KeyPressed(char key, | |
366 KeyboardModifiers modifiers) | |
367 { | |
368 if (interactor_) | |
369 { | |
370 interactor_->KeyPressed(*this, key, modifiers, GetStatusBar()); | |
371 } | |
372 } | |
373 } |