comparison Samples/Deprecated/Sdl/TrackerSampleApp.cpp @ 1348:eac254fb6791 broker

Moved Application/Samples/* to Application/Samples/Deprecated/* (remaining) + moved Samples/* to Samples/Deprecated/*
author Benjamin Golinvaux <bgo@osimis.io>
date Tue, 07 Apr 2020 14:31:28 +0200
parents Samples/Sdl/TrackerSampleApp.cpp@8a0a62189f46
children
comparison
equal deleted inserted replaced
1347:bfd77672d825 1348:eac254fb6791
1 /**
2 * Stone of Orthanc
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium
6 *
7 * This program is free software: you can redistribute it and/or
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.
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
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
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/
20
21 #include "TrackerSampleApp.h"
22
23 #include "../../Framework/OpenGL/SdlOpenGLContext.h"
24 #include "../../Framework/Scene2D/CairoCompositor.h"
25 #include "../../Framework/Scene2D/ColorTextureSceneLayer.h"
26 #include "../../Framework/Scene2D/OpenGLCompositor.h"
27 #include "../../Framework/Scene2D/PanSceneTracker.h"
28 #include "../../Framework/Scene2D/RotateSceneTracker.h"
29 #include "../../Framework/Scene2D/Scene2D.h"
30 #include "../../Framework/Scene2D/ZoomSceneTracker.h"
31 #include "../../Framework/Scene2DViewport/UndoStack.h"
32 #include "../../Framework/Scene2DViewport/CreateAngleMeasureTracker.h"
33 #include "../../Framework/Scene2DViewport/CreateLineMeasureTracker.h"
34 #include "../../Framework/StoneInitialization.h"
35
36 // From Orthanc framework
37 #include <Core/Logging.h>
38 #include <Core/OrthancException.h>
39 #include <Core/Images/Image.h>
40 #include <Core/Images/ImageProcessing.h>
41 #include <Core/Images/PngWriter.h>
42
43 #include <boost/ref.hpp>
44 #include <boost/make_shared.hpp>
45 #include <SDL.h>
46
47 #include <stdio.h>
48
49 namespace OrthancStone
50 {
51 const char* MeasureToolToString(size_t i)
52 {
53 static const char* descs[] = {
54 "GuiTool_Rotate",
55 "GuiTool_Pan",
56 "GuiTool_Zoom",
57 "GuiTool_LineMeasure",
58 "GuiTool_CircleMeasure",
59 "GuiTool_AngleMeasure",
60 "GuiTool_EllipseMeasure",
61 "GuiTool_LAST"
62 };
63 if (i >= GuiTool_LAST)
64 {
65 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "Wrong tool index");
66 }
67 return descs[i];
68 }
69
70 void TrackerSampleApp::SelectNextTool()
71 {
72 currentTool_ = static_cast<GuiTool>(currentTool_ + 1);
73 if (currentTool_ == GuiTool_LAST)
74 currentTool_ = static_cast<GuiTool>(0);;
75 printf("Current tool is now: %s\n", MeasureToolToString(currentTool_));
76 }
77
78 void TrackerSampleApp::DisplayInfoText()
79 {
80 // do not try to use stuff too early!
81 std::stringstream msg;
82
83 for (std::map<std::string, std::string>::const_iterator kv = infoTextMap_.begin();
84 kv != infoTextMap_.end(); ++kv)
85 {
86 msg << kv->first << " : " << kv->second << std::endl;
87 }
88 std::string msgS = msg.str();
89
90 TextSceneLayer* layerP = NULL;
91 if (controller_->GetScene().HasLayer(FIXED_INFOTEXT_LAYER_ZINDEX))
92 {
93 TextSceneLayer& layer = dynamic_cast<TextSceneLayer&>(
94 controller_->GetScene().GetLayer(FIXED_INFOTEXT_LAYER_ZINDEX));
95 layerP = &layer;
96 }
97 else
98 {
99 std::unique_ptr<TextSceneLayer> layer(new TextSceneLayer);
100 layerP = layer.get();
101 layer->SetColor(0, 255, 0);
102 layer->SetFontIndex(1);
103 layer->SetBorder(20);
104 layer->SetAnchor(BitmapAnchor_TopLeft);
105 //layer->SetPosition(0,0);
106 controller_->GetScene().SetLayer(FIXED_INFOTEXT_LAYER_ZINDEX, layer.release());
107 }
108 // position the fixed info text in the upper right corner
109 layerP->SetText(msgS.c_str());
110 double cX = GetCompositor().GetCanvasWidth() * (-0.5);
111 double cY = GetCompositor().GetCanvasHeight() * (-0.5);
112 controller_->GetScene().GetCanvasToSceneTransform().Apply(cX,cY);
113 layerP->SetPosition(cX, cY);
114 }
115
116 void TrackerSampleApp::DisplayFloatingCtrlInfoText(const PointerEvent& e)
117 {
118 ScenePoint2D p = e.GetMainPosition().Apply(controller_->GetScene().GetCanvasToSceneTransform());
119
120 char buf[128];
121 sprintf(buf, "S:(%0.02f,%0.02f) C:(%0.02f,%0.02f)",
122 p.GetX(), p.GetY(),
123 e.GetMainPosition().GetX(), e.GetMainPosition().GetY());
124
125 if (controller_->GetScene().HasLayer(FLOATING_INFOTEXT_LAYER_ZINDEX))
126 {
127 TextSceneLayer& layer =
128 dynamic_cast<TextSceneLayer&>(controller_->GetScene().GetLayer(FLOATING_INFOTEXT_LAYER_ZINDEX));
129 layer.SetText(buf);
130 layer.SetPosition(p.GetX(), p.GetY());
131 }
132 else
133 {
134 std::unique_ptr<TextSceneLayer> layer(new TextSceneLayer);
135 layer->SetColor(0, 255, 0);
136 layer->SetText(buf);
137 layer->SetBorder(20);
138 layer->SetAnchor(BitmapAnchor_BottomCenter);
139 layer->SetPosition(p.GetX(), p.GetY());
140 controller_->GetScene().SetLayer(FLOATING_INFOTEXT_LAYER_ZINDEX, layer.release());
141 }
142 }
143
144 void TrackerSampleApp::HideInfoText()
145 {
146 controller_->GetScene().DeleteLayer(FLOATING_INFOTEXT_LAYER_ZINDEX);
147 }
148
149 ScenePoint2D TrackerSampleApp::GetRandomPointInScene() const
150 {
151 unsigned int w = GetCompositor().GetCanvasWidth();
152 LOG(TRACE) << "GetCompositor().GetCanvasWidth() = " <<
153 GetCompositor().GetCanvasWidth();
154 unsigned int h = GetCompositor().GetCanvasHeight();
155 LOG(TRACE) << "GetCompositor().GetCanvasHeight() = " <<
156 GetCompositor().GetCanvasHeight();
157
158 if ((w >= RAND_MAX) || (h >= RAND_MAX))
159 LOG(WARNING) << "Canvas is too big : tools will not be randomly placed";
160
161 int x = rand() % w;
162 int y = rand() % h;
163 LOG(TRACE) << "random x = " << x << "random y = " << y;
164
165 ScenePoint2D p = controller_->GetViewport().GetPixelCenterCoordinates(x, y);
166 LOG(TRACE) << "--> p.GetX() = " << p.GetX() << " p.GetY() = " << p.GetY();
167
168 ScenePoint2D r = p.Apply(controller_->GetScene().GetCanvasToSceneTransform());
169 LOG(TRACE) << "--> r.GetX() = " << r.GetX() << " r.GetY() = " << r.GetY();
170 return r;
171 }
172
173 void TrackerSampleApp::CreateRandomMeasureTool()
174 {
175 static bool srandCalled = false;
176 if (!srandCalled)
177 {
178 srand(42);
179 srandCalled = true;
180 }
181
182 int i = rand() % 2;
183 LOG(TRACE) << "random i = " << i;
184 switch (i)
185 {
186 case 0:
187 // line measure
188 {
189 boost::shared_ptr<CreateLineMeasureCommand> cmd =
190 boost::make_shared<CreateLineMeasureCommand>(
191 boost::ref(IObserver::GetBroker()),
192 controller_,
193 GetRandomPointInScene());
194 cmd->SetEnd(GetRandomPointInScene());
195 controller_->PushCommand(cmd);
196 }
197 break;
198 case 1:
199 // angle measure
200 {
201 boost::shared_ptr<CreateAngleMeasureCommand> cmd =
202 boost::make_shared<CreateAngleMeasureCommand>(
203 boost::ref(IObserver::GetBroker()),
204 controller_,
205 GetRandomPointInScene());
206 cmd->SetCenter(GetRandomPointInScene());
207 cmd->SetSide2End(GetRandomPointInScene());
208 controller_->PushCommand(cmd);
209 }
210 break;
211 }
212 }
213
214 void TrackerSampleApp::HandleApplicationEvent(
215 const SDL_Event & event)
216 {
217 DisplayInfoText();
218
219 if (event.type == SDL_MOUSEMOTION)
220 {
221 int scancodeCount = 0;
222 const uint8_t* keyboardState = SDL_GetKeyboardState(&scancodeCount);
223
224 if (activeTracker_.get() == NULL &&
225 SDL_SCANCODE_LALT < scancodeCount &&
226 keyboardState[SDL_SCANCODE_LALT])
227 {
228 // The "left-ctrl" key is down, while no tracker is present
229 // Let's display the info text
230 PointerEvent e;
231 e.AddPosition(controller_->GetViewport().GetPixelCenterCoordinates(
232 event.button.x, event.button.y));
233
234 DisplayFloatingCtrlInfoText(e);
235 }
236 else if (activeTracker_.get() != NULL)
237 {
238 HideInfoText();
239 //LOG(TRACE) << "(event.type == SDL_MOUSEMOTION)";
240 if (activeTracker_.get() != NULL)
241 {
242 //LOG(TRACE) << "(activeTracker_.get() != NULL)";
243 PointerEvent e;
244 e.AddPosition(controller_->GetViewport().GetPixelCenterCoordinates(
245 event.button.x, event.button.y));
246
247 //LOG(TRACE) << "event.button.x = " << event.button.x << " " <<
248 // "event.button.y = " << event.button.y;
249 LOG(TRACE) << "activeTracker_->PointerMove(e); " <<
250 e.GetMainPosition().GetX() << " " << e.GetMainPosition().GetY();
251
252 activeTracker_->PointerMove(e);
253 if (!activeTracker_->IsAlive())
254 activeTracker_.reset();
255 }
256 }
257 else
258 {
259 HideInfoText();
260
261 PointerEvent e;
262 e.AddPosition(controller_->GetViewport().GetPixelCenterCoordinates(event.button.x, event.button.y));
263
264 ScenePoint2D scenePos = e.GetMainPosition().Apply(
265 controller_->GetScene().GetCanvasToSceneTransform());
266 //auto measureTools = GetController()->HitTestMeasureTools(scenePos);
267 //LOG(TRACE) << "# of hit tests: " << measureTools.size();
268
269 // this returns the collection of measuring tools where hit test is true
270 std::vector<boost::shared_ptr<MeasureTool> > measureTools = controller_->HitTestMeasureTools(scenePos);
271
272 // let's refresh the measuring tools highlighted state
273 // first let's tag them as "unhighlighted"
274 controller_->ResetMeasuringToolsHighlight();
275
276 // then immediately take the first one and ask it to highlight the
277 // measuring tool UI part that is hot
278 if (measureTools.size() > 0)
279 {
280 measureTools[0]->Highlight(scenePos);
281 }
282 }
283 }
284 else if (event.type == SDL_MOUSEBUTTONUP)
285 {
286 if (activeTracker_)
287 {
288 PointerEvent e;
289 e.AddPosition(controller_->GetViewport().GetPixelCenterCoordinates(event.button.x, event.button.y));
290 activeTracker_->PointerUp(e);
291 if (!activeTracker_->IsAlive())
292 activeTracker_.reset();
293 }
294 }
295 else if (event.type == SDL_MOUSEBUTTONDOWN)
296 {
297 PointerEvent e;
298 e.AddPosition(controller_->GetViewport().GetPixelCenterCoordinates(
299 event.button.x, event.button.y));
300 if (activeTracker_)
301 {
302 activeTracker_->PointerDown(e);
303 if (!activeTracker_->IsAlive())
304 activeTracker_.reset();
305 }
306 else
307 {
308 // we ATTEMPT to create a tracker if need be
309 activeTracker_ = CreateSuitableTracker(event, e);
310 }
311 }
312 else if (event.type == SDL_KEYDOWN &&
313 event.key.repeat == 0 /* Ignore key bounce */)
314 {
315 switch (event.key.keysym.sym)
316 {
317 case SDLK_ESCAPE:
318 if (activeTracker_)
319 {
320 activeTracker_->Cancel();
321 if (!activeTracker_->IsAlive())
322 activeTracker_.reset();
323 }
324 break;
325
326 case SDLK_t:
327 if (!activeTracker_)
328 SelectNextTool();
329 else
330 {
331 LOG(WARNING) << "You cannot change the active tool when an interaction"
332 " is taking place";
333 }
334 break;
335
336 case SDLK_m:
337 CreateRandomMeasureTool();
338 break;
339 case SDLK_s:
340 controller_->FitContent(GetCompositor().GetCanvasWidth(),
341 GetCompositor().GetCanvasHeight());
342 break;
343
344 case SDLK_z:
345 LOG(TRACE) << "SDLK_z has been pressed. event.key.keysym.mod == " << event.key.keysym.mod;
346 if (event.key.keysym.mod & KMOD_CTRL)
347 {
348 if (controller_->CanUndo())
349 {
350 LOG(TRACE) << "Undoing...";
351 controller_->Undo();
352 }
353 else
354 {
355 LOG(WARNING) << "Nothing to undo!!!";
356 }
357 }
358 break;
359
360 case SDLK_y:
361 LOG(TRACE) << "SDLK_y has been pressed. event.key.keysym.mod == " << event.key.keysym.mod;
362 if (event.key.keysym.mod & KMOD_CTRL)
363 {
364 if (controller_->CanRedo())
365 {
366 LOG(TRACE) << "Redoing...";
367 controller_->Redo();
368 }
369 else
370 {
371 LOG(WARNING) << "Nothing to redo!!!";
372 }
373 }
374 break;
375
376 case SDLK_c:
377 TakeScreenshot(
378 "screenshot.png",
379 GetCompositor().GetCanvasWidth(),
380 GetCompositor().GetCanvasHeight());
381 break;
382
383 default:
384 break;
385 }
386 }
387 }
388
389
390 void TrackerSampleApp::OnSceneTransformChanged(
391 const ViewportController::SceneTransformChanged& message)
392 {
393 DisplayInfoText();
394 }
395
396 boost::shared_ptr<IFlexiblePointerTracker> TrackerSampleApp::CreateSuitableTracker(
397 const SDL_Event & event,
398 const PointerEvent & e)
399 {
400 using namespace Orthanc;
401
402 switch (event.button.button)
403 {
404 case SDL_BUTTON_MIDDLE:
405 return boost::shared_ptr<IFlexiblePointerTracker>(new PanSceneTracker
406 (controller_, e));
407
408 case SDL_BUTTON_RIGHT:
409 return boost::shared_ptr<IFlexiblePointerTracker>(new ZoomSceneTracker
410 (controller_, e, GetCompositor().GetCanvasHeight()));
411
412 case SDL_BUTTON_LEFT:
413 {
414 //LOG(TRACE) << "CreateSuitableTracker: case SDL_BUTTON_LEFT:";
415 // TODO: we need to iterate on the set of measuring tool and perform
416 // a hit test to check if a tracker needs to be created for edition.
417 // Otherwise, depending upon the active tool, we might want to create
418 // a "measuring tool creation" tracker
419
420 // TODO: if there are conflicts, we should prefer a tracker that
421 // pertains to the type of measuring tool currently selected (TBD?)
422 boost::shared_ptr<IFlexiblePointerTracker> hitTestTracker = TrackerHitTest(e);
423
424 if (hitTestTracker != NULL)
425 {
426 //LOG(TRACE) << "hitTestTracker != NULL";
427 return hitTestTracker;
428 }
429 else
430 {
431 switch (currentTool_)
432 {
433 case GuiTool_Rotate:
434 //LOG(TRACE) << "Creating RotateSceneTracker";
435 return boost::shared_ptr<IFlexiblePointerTracker>(new RotateSceneTracker(
436 controller_, e));
437 case GuiTool_Pan:
438 return boost::shared_ptr<IFlexiblePointerTracker>(new PanSceneTracker(
439 controller_, e));
440 case GuiTool_Zoom:
441 return boost::shared_ptr<IFlexiblePointerTracker>(new ZoomSceneTracker(
442 controller_, e, GetCompositor().GetCanvasHeight()));
443 //case GuiTool_AngleMeasure:
444 // return new AngleMeasureTracker(GetScene(), e);
445 //case GuiTool_CircleMeasure:
446 // return new CircleMeasureTracker(GetScene(), e);
447 //case GuiTool_EllipseMeasure:
448 // return new EllipseMeasureTracker(GetScene(), e);
449 case GuiTool_LineMeasure:
450 return boost::shared_ptr<IFlexiblePointerTracker>(new CreateLineMeasureTracker(
451 IObserver::GetBroker(), controller_, e));
452 case GuiTool_AngleMeasure:
453 return boost::shared_ptr<IFlexiblePointerTracker>(new CreateAngleMeasureTracker(
454 IObserver::GetBroker(), controller_, e));
455 case GuiTool_CircleMeasure:
456 LOG(ERROR) << "Not implemented yet!";
457 return boost::shared_ptr<IFlexiblePointerTracker>();
458 case GuiTool_EllipseMeasure:
459 LOG(ERROR) << "Not implemented yet!";
460 return boost::shared_ptr<IFlexiblePointerTracker>();
461 default:
462 throw OrthancException(ErrorCode_InternalError, "Wrong tool!");
463 }
464 }
465 }
466 default:
467 return boost::shared_ptr<IFlexiblePointerTracker>();
468 }
469 }
470
471
472 TrackerSampleApp::TrackerSampleApp(MessageBroker& broker) : IObserver(broker)
473 , currentTool_(GuiTool_Rotate)
474 , undoStack_(new UndoStack)
475 , viewport_("Hello", 1024, 1024, false) // False means we do NOT let Windows treat this as a legacy application that needs to be scaled
476 {
477 controller_ = boost::shared_ptr<ViewportController>(
478 new ViewportController(undoStack_, broker, viewport_));
479
480 controller_->RegisterObserverCallback(
481 new Callable<TrackerSampleApp, ViewportController::SceneTransformChanged>
482 (*this, &TrackerSampleApp::OnSceneTransformChanged));
483
484 TEXTURE_2x2_1_ZINDEX = 1;
485 TEXTURE_1x1_ZINDEX = 2;
486 TEXTURE_2x2_2_ZINDEX = 3;
487 LINESET_1_ZINDEX = 4;
488 LINESET_2_ZINDEX = 5;
489 FLOATING_INFOTEXT_LAYER_ZINDEX = 6;
490 FIXED_INFOTEXT_LAYER_ZINDEX = 7;
491 }
492
493 void TrackerSampleApp::PrepareScene()
494 {
495 // Texture of 2x2 size
496 {
497 Orthanc::Image i(Orthanc::PixelFormat_RGB24, 2, 2, false);
498
499 uint8_t* p = reinterpret_cast<uint8_t*>(i.GetRow(0));
500 p[0] = 255;
501 p[1] = 0;
502 p[2] = 0;
503
504 p[3] = 0;
505 p[4] = 255;
506 p[5] = 0;
507
508 p = reinterpret_cast<uint8_t*>(i.GetRow(1));
509 p[0] = 0;
510 p[1] = 0;
511 p[2] = 255;
512
513 p[3] = 255;
514 p[4] = 0;
515 p[5] = 0;
516
517 controller_->GetScene().SetLayer(TEXTURE_2x2_1_ZINDEX, new ColorTextureSceneLayer(i));
518
519 std::unique_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i));
520 l->SetOrigin(-3, 2);
521 l->SetPixelSpacing(1.5, 1);
522 l->SetAngle(20.0 / 180.0 * M_PI);
523 controller_->GetScene().SetLayer(TEXTURE_2x2_2_ZINDEX, l.release());
524 }
525
526 // Texture of 1x1 size
527 {
528 Orthanc::Image i(Orthanc::PixelFormat_RGB24, 1, 1, false);
529
530 uint8_t* p = reinterpret_cast<uint8_t*>(i.GetRow(0));
531 p[0] = 255;
532 p[1] = 0;
533 p[2] = 0;
534
535 std::unique_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i));
536 l->SetOrigin(-2, 1);
537 l->SetAngle(20.0 / 180.0 * M_PI);
538 controller_->GetScene().SetLayer(TEXTURE_1x1_ZINDEX, l.release());
539 }
540
541 // Some lines
542 {
543 std::unique_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer);
544
545 layer->SetThickness(1);
546
547 PolylineSceneLayer::Chain chain;
548 chain.push_back(ScenePoint2D(0 - 0.5, 0 - 0.5));
549 chain.push_back(ScenePoint2D(0 - 0.5, 2 - 0.5));
550 chain.push_back(ScenePoint2D(2 - 0.5, 2 - 0.5));
551 chain.push_back(ScenePoint2D(2 - 0.5, 0 - 0.5));
552 layer->AddChain(chain, true, 255, 0, 0);
553
554 chain.clear();
555 chain.push_back(ScenePoint2D(-5, -5));
556 chain.push_back(ScenePoint2D(5, -5));
557 chain.push_back(ScenePoint2D(5, 5));
558 chain.push_back(ScenePoint2D(-5, 5));
559 layer->AddChain(chain, true, 0, 255, 0);
560
561 double dy = 1.01;
562 chain.clear();
563 chain.push_back(ScenePoint2D(-4, -4));
564 chain.push_back(ScenePoint2D(4, -4 + dy));
565 chain.push_back(ScenePoint2D(-4, -4 + 2.0 * dy));
566 chain.push_back(ScenePoint2D(4, 2));
567 layer->AddChain(chain, false, 0, 0, 255);
568
569 controller_->GetScene().SetLayer(LINESET_1_ZINDEX, layer.release());
570 }
571
572 // Some text
573 {
574 std::unique_ptr<TextSceneLayer> layer(new TextSceneLayer);
575 layer->SetText("Hello");
576 controller_->GetScene().SetLayer(LINESET_2_ZINDEX, layer.release());
577 }
578 }
579
580
581 void TrackerSampleApp::DisableTracker()
582 {
583 if (activeTracker_)
584 {
585 activeTracker_->Cancel();
586 activeTracker_.reset();
587 }
588 }
589
590 void TrackerSampleApp::TakeScreenshot(const std::string& target,
591 unsigned int canvasWidth,
592 unsigned int canvasHeight)
593 {
594 CairoCompositor compositor(controller_->GetScene(), canvasWidth, canvasHeight);
595 compositor.SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT, FONT_SIZE_0, Orthanc::Encoding_Latin1);
596 compositor.Refresh();
597
598 Orthanc::ImageAccessor canvas;
599 compositor.GetCanvas().GetReadOnlyAccessor(canvas);
600
601 Orthanc::Image png(Orthanc::PixelFormat_RGB24, canvas.GetWidth(), canvas.GetHeight(), false);
602 Orthanc::ImageProcessing::Convert(png, canvas);
603
604 Orthanc::PngWriter writer;
605 writer.WriteToFile(target, png);
606 }
607
608
609 boost::shared_ptr<IFlexiblePointerTracker> TrackerSampleApp::TrackerHitTest(const PointerEvent & e)
610 {
611 // std::vector<boost::shared_ptr<MeasureTool>> measureTools_;
612 ScenePoint2D scenePos = e.GetMainPosition().Apply(
613 controller_->GetScene().GetCanvasToSceneTransform());
614
615 std::vector<boost::shared_ptr<MeasureTool> > measureTools = controller_->HitTestMeasureTools(scenePos);
616
617 if (measureTools.size() > 0)
618 {
619 return measureTools[0]->CreateEditionTracker(e);
620 }
621 return boost::shared_ptr<IFlexiblePointerTracker>();
622 }
623
624 static void GLAPIENTRY
625 OpenGLMessageCallback(GLenum source,
626 GLenum type,
627 GLuint id,
628 GLenum severity,
629 GLsizei length,
630 const GLchar* message,
631 const void* userParam)
632 {
633 if (severity != GL_DEBUG_SEVERITY_NOTIFICATION)
634 {
635 fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
636 (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""),
637 type, severity, message);
638 }
639 }
640
641 static bool g_stopApplication = false;
642
643 ICompositor& TrackerSampleApp::GetCompositor()
644 {
645 using namespace Orthanc;
646 try
647 {
648 SdlViewport& viewport = dynamic_cast<SdlViewport&>(viewport_);
649 return viewport.GetCompositor();
650 }
651 catch (std::bad_cast e)
652 {
653 throw OrthancException(ErrorCode_InternalError, "Wrong viewport type!");
654 }
655 }
656
657 const ICompositor& TrackerSampleApp::GetCompositor() const
658 {
659 using namespace Orthanc;
660 try
661 {
662 SdlViewport& viewport = const_cast<SdlViewport&>(dynamic_cast<const SdlViewport&>(viewport_));
663 return viewport.GetCompositor();
664 }
665 catch (std::bad_cast e)
666 {
667 throw OrthancException(ErrorCode_InternalError, "Wrong viewport type!");
668 }
669 }
670
671
672 void TrackerSampleApp::Run()
673 {
674 controller_->FitContent(viewport_.GetCanvasWidth(), viewport_.GetCanvasHeight());
675
676 glEnable(GL_DEBUG_OUTPUT);
677 glDebugMessageCallback(OpenGLMessageCallback, 0);
678
679 GetCompositor().SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT,
680 FONT_SIZE_0, Orthanc::Encoding_Latin1);
681 GetCompositor().SetFont(1, Orthanc::EmbeddedResources::UBUNTU_FONT,
682 FONT_SIZE_1, Orthanc::Encoding_Latin1);
683
684 while (!g_stopApplication)
685 {
686 GetCompositor().Refresh();
687
688 SDL_Event event;
689 while (!g_stopApplication && SDL_PollEvent(&event))
690 {
691 if (event.type == SDL_QUIT)
692 {
693 g_stopApplication = true;
694 break;
695 }
696 else if (event.type == SDL_WINDOWEVENT &&
697 event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
698 {
699 DisableTracker(); // was: tracker.reset(NULL);
700 }
701 else if (event.type == SDL_KEYDOWN &&
702 event.key.repeat == 0 /* Ignore key bounce */)
703 {
704 switch (event.key.keysym.sym)
705 {
706 case SDLK_f:
707 viewport_.GetWindow().ToggleMaximize();
708 break;
709
710 case SDLK_q:
711 g_stopApplication = true;
712 break;
713 default:
714 break;
715 }
716 }
717 HandleApplicationEvent(event);
718 }
719 SDL_Delay(1);
720 }
721 }
722
723 void TrackerSampleApp::SetInfoDisplayMessage(
724 std::string key, std::string value)
725 {
726 if (value == "")
727 infoTextMap_.erase(key);
728 else
729 infoTextMap_[key] = value;
730 DisplayInfoText();
731 }
732
733 }