comparison Applications/Samples/SingleFrameEditorApplication.h @ 325:37ab9d83dc9b am-2

reactivate SingleFrameApplication sample + Added SingleFrameEditorApplication (SDL only)
author am@osimis.io
date Tue, 16 Oct 2018 11:30:00 +0200
parents
children 612238b3f3e8
comparison
equal deleted inserted replaced
324:29a79b8c3d39 325:37ab9d83dc9b
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-2018 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
22 #pragma once
23
24 #include "SampleApplicationBase.h"
25
26 #include "../../Framework/Layers/OrthancFrameLayerSource.h"
27 #include "../../Framework/Widgets/LayerWidget.h"
28
29 #include <Core/Logging.h>
30
31 namespace OrthancStone
32 {
33 namespace Samples
34 {
35 class SingleFrameEditorApplication :
36 public SampleApplicationBase,
37 public IObserver
38 {
39 enum Tools
40 {
41 Tools_Crop,
42 Tools_Windowing,
43 Tools_Zoom,
44 Tools_Pan
45 };
46
47 enum Actions
48 {
49 Actions_Invert,
50 Actions_RotateLeft,
51 Actions_RotateRight
52 };
53
54 private:
55 class Interactor : public IWorldSceneInteractor
56 {
57 private:
58 SingleFrameEditorApplication& application_;
59
60 public:
61 Interactor(SingleFrameEditorApplication& application) :
62 application_(application)
63 {
64 }
65
66 virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
67 const ViewportGeometry& view,
68 MouseButton button,
69 KeyboardModifiers modifiers,
70 double x,
71 double y,
72 IStatusBar* statusBar)
73 {
74 switch (application_.currentTool_) {
75 case Tools_Crop:
76 case Tools_Windowing:
77 case Tools_Zoom:
78 case Tools_Pan:
79 // TODO return the right mouse tracker
80 return NULL;
81 }
82
83 return NULL;
84 }
85
86 virtual void MouseOver(CairoContext& context,
87 WorldSceneWidget& widget,
88 const ViewportGeometry& view,
89 double x,
90 double y,
91 IStatusBar* statusBar)
92 {
93 if (statusBar != NULL)
94 {
95 Vector p = dynamic_cast<LayerWidget&>(widget).GetSlice().MapSliceToWorldCoordinates(x, y);
96
97 char buf[64];
98 sprintf(buf, "X = %.02f Y = %.02f Z = %.02f (in cm)",
99 p[0] / 10.0, p[1] / 10.0, p[2] / 10.0);
100 statusBar->SetMessage(buf);
101 }
102 }
103
104 virtual void MouseWheel(WorldSceneWidget& widget,
105 MouseWheelDirection direction,
106 KeyboardModifiers modifiers,
107 IStatusBar* statusBar)
108 {
109 }
110
111 virtual void KeyPressed(WorldSceneWidget& widget,
112 char key,
113 KeyboardModifiers modifiers,
114 IStatusBar* statusBar)
115 {
116 switch (key)
117 {
118 case 's':
119 widget.SetDefaultView();
120 break;
121 case 'p':
122 application_.currentTool_ = Tools_Pan;
123 break;
124 case 'z':
125 application_.currentTool_ = Tools_Zoom;
126 break;
127 case 'c':
128 application_.currentTool_ = Tools_Crop;
129 break;
130 case 'w':
131 application_.currentTool_ = Tools_Windowing;
132 break;
133 case 'i':
134 application_.Invert();
135 break;
136 case 'r':
137 if (modifiers == KeyboardModifiers_None)
138 application_.Rotate(90);
139 else
140 application_.Rotate(-90);
141 break;
142 case 'e':
143 application_.Export();
144 break;
145 default:
146 break;
147 }
148 }
149 };
150
151 void OnMainWidgetGeometryReady(const ILayerSource::GeometryReadyMessage& message)
152 {
153 mainWidget_->SetDefaultView();
154 }
155
156 LayerWidget* mainWidget_; // ownership is transfered to the application context
157 std::unique_ptr<Interactor> mainWidgetInteractor_;
158 std::unique_ptr<OrthancApiClient> orthancApiClient_;
159 Tools currentTool_;
160
161 const OrthancFrameLayerSource* source_;
162 unsigned int slice_;
163
164 public:
165 SingleFrameEditorApplication(MessageBroker& broker) :
166 IObserver(broker),
167 currentTool_(Tools_Zoom),
168 source_(NULL),
169 slice_(0)
170 {
171 }
172
173 virtual void DeclareStartupOptions(boost::program_options::options_description& options)
174 {
175 boost::program_options::options_description generic("Sample options");
176 generic.add_options()
177 ("instance", boost::program_options::value<std::string>(),
178 "Orthanc ID of the instance")
179 ("frame", boost::program_options::value<unsigned int>()->default_value(0),
180 "Number of the frame, for multi-frame DICOM instances")
181 ;
182
183 options.add(generic);
184 }
185
186 virtual void Initialize(StoneApplicationContext* context,
187 IStatusBar& statusBar,
188 const boost::program_options::variables_map& parameters)
189 {
190 using namespace OrthancStone;
191
192 context_ = context;
193
194 statusBar.SetMessage("Use the key \"s\" to reinitialize the layout, \"p\" to pan, \"z\" to zoom, \"c\" to crop, \"i\" to invert, \"w\" to change windowing, \"r\" to rotate cw, \"shift+r\" to rotate ccw");
195
196 if (parameters.count("instance") != 1)
197 {
198 LOG(ERROR) << "The instance ID is missing";
199 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
200 }
201
202 std::string instance = parameters["instance"].as<std::string>();
203 int frame = parameters["frame"].as<unsigned int>();
204
205 orthancApiClient_.reset(new OrthancApiClient(IObserver::broker_, context_->GetWebService()));
206 mainWidget_ = new LayerWidget(broker_, "main-widget");
207
208 std::auto_ptr<OrthancFrameLayerSource> layer(new OrthancFrameLayerSource(broker_, *orthancApiClient_));
209 source_ = layer.get();
210 layer->LoadFrame(instance, frame);
211 layer->RegisterObserverCallback(new Callable<SingleFrameEditorApplication, ILayerSource::GeometryReadyMessage>(*this, &SingleFrameEditorApplication::OnMainWidgetGeometryReady));
212 mainWidget_->AddLayer(layer.release());
213
214 mainWidget_->SetTransmitMouseOver(true);
215
216 mainWidgetInteractor_.reset(new Interactor(*this));
217 mainWidget_->SetInteractor(*mainWidgetInteractor_);
218 }
219
220 virtual void Finalize() {}
221 virtual IWidget* GetCentralWidget() {return mainWidget_;}
222
223 void Invert()
224 {
225 // TODO
226 }
227
228 void Rotate(int degrees)
229 {
230 // TODO
231 }
232
233 void Export()
234 {
235 // TODO: export dicom file to a temporary file
236 }
237 };
238
239
240 }
241 }