Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file GUITLLogicPhasesTrackerWindow.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @date Oct/Nov 2003
19 : ///
20 : // A window displaying the phase diagram of a tl-logic
21 : /****************************************************************************/
22 : #include <config.h>
23 :
24 : #include <vector>
25 : #include <iostream>
26 : #include <utils/gui/windows/GUIMainWindow.h>
27 : #include <utils/gui/div/GLHelper.h>
28 : #include "GUITLLogicPhasesTrackerWindow.h"
29 : #include <microsim/traffic_lights/MSTrafficLightLogic.h>
30 : #include <microsim/output/MSInductLoop.h>
31 : #include <microsim/MSLink.h>
32 : #include <utils/common/ToString.h>
33 : #include <utils/common/MsgHandler.h>
34 : #include <guisim/GUITrafficLightLogicWrapper.h>
35 : #include <utils/gui/windows/GUIAppEnum.h>
36 : #include <utils/gui/images/GUIIconSubSys.h>
37 : #include <utils/gui/settings/GUIVisualizationSettings.h>
38 : #include <utils/gui/div/GUIDesigns.h>
39 : #include <foreign/fontstash/fontstash.h>
40 : #include <utils/gui/globjects/GLIncludes.h>
41 :
42 :
43 : // ===========================================================================
44 : // static member initialisation
45 : // ===========================================================================
46 : int GUITLLogicPhasesTrackerWindow::myLastY(-1);
47 :
48 : // ===========================================================================
49 : // member method definitions
50 : // ===========================================================================
51 : /* -------------------------------------------------------------------------
52 : * GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel-callbacks
53 : * ----------------------------------------------------------------------- */
54 : FXDEFMAP(GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel) GUITLLogicPhasesTrackerPanelMap[] = {
55 : FXMAPFUNC(SEL_CONFIGURE, 0, GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::onConfigure),
56 : FXMAPFUNC(SEL_PAINT, 0, GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::onPaint),
57 : FXMAPFUNC(SEL_MOTION, 0, GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::onMouseMove),
58 :
59 : };
60 :
61 : // Macro for the GLTestApp class hierarchy implementation
62 0 : FXIMPLEMENT(GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel, FXGLCanvas, GUITLLogicPhasesTrackerPanelMap, ARRAYNUMBER(GUITLLogicPhasesTrackerPanelMap))
63 :
64 :
65 :
66 : /* -------------------------------------------------------------------------
67 : * GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel-methods
68 : * ----------------------------------------------------------------------- */
69 0 : GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::GUITLLogicPhasesTrackerPanel(
70 : FXComposite* c, GUIMainWindow& app,
71 0 : GUITLLogicPhasesTrackerWindow& parent) :
72 0 : FXGLCanvas(c, app.getGLVisual(), app.getBuildGLCanvas(), (FXObject*) nullptr, (FXSelector) 0, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y/*, 0, 0, 300, 200*/),
73 0 : myParent(&parent)
74 0 : {}
75 :
76 :
77 0 : GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::~GUITLLogicPhasesTrackerPanel() {}
78 :
79 :
80 : long
81 0 : GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::onConfigure(FXObject*, FXSelector, void*) {
82 0 : if (makeCurrent()) {
83 : int widthInPixels = getWidth();
84 : int heightInPixels = getHeight();
85 0 : if (widthInPixels != 0 && heightInPixels != 0) {
86 0 : glViewport(0, 0, widthInPixels - 1, heightInPixels - 1);
87 0 : glClearColor(0, 0, 0, 1);
88 0 : glDisable(GL_DEPTH_TEST);
89 0 : glDisable(GL_LIGHTING);
90 0 : glDisable(GL_LINE_SMOOTH);
91 0 : glEnable(GL_BLEND);
92 0 : glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
93 0 : glEnable(GL_ALPHA_TEST);
94 0 : glDisable(GL_COLOR_MATERIAL);
95 0 : glLineWidth(1);
96 0 : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
97 : }
98 : }
99 0 : return 1;
100 : }
101 :
102 :
103 : long
104 0 : GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::onPaint(
105 : FXObject*, FXSelector, void*) {
106 0 : if (!isEnabled()) {
107 : return 1;
108 : }
109 0 : if (makeCurrent()) {
110 : int widthInPixels = getWidth();
111 : int heightInPixels = getHeight();
112 0 : if (widthInPixels != 0 && heightInPixels != 0) {
113 0 : glViewport(0, 0, widthInPixels - 1, heightInPixels - 1);
114 0 : glClearColor(0, 0, 0, 1);
115 0 : glDisable(GL_DEPTH_TEST);
116 0 : glDisable(GL_LIGHTING);
117 0 : glDisable(GL_LINE_SMOOTH);
118 0 : glEnable(GL_BLEND);
119 0 : glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
120 0 : glEnable(GL_ALPHA_TEST);
121 0 : glDisable(GL_COLOR_MATERIAL);
122 0 : glLineWidth(1);
123 0 : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
124 : // draw
125 0 : glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
126 0 : myParent->drawValues(*this);
127 0 : swapBuffers();
128 : }
129 0 : makeNonCurrent();
130 : }
131 : return 1;
132 : }
133 :
134 :
135 : long
136 0 : GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::onMouseMove(FXObject*, FXSelector, void* ptr) {
137 : FXEvent* event = (FXEvent*) ptr;
138 0 : myMousePos.setx(event->win_x);
139 0 : myMousePos.sety(event->win_y);
140 0 : onPaint(nullptr, 0, nullptr);
141 0 : return 1;
142 : }
143 :
144 : /* -------------------------------------------------------------------------
145 : * GUITLLogicPhasesTrackerWindow - FOX callback mapping
146 : * ----------------------------------------------------------------------- */
147 : FXDEFMAP(GUITLLogicPhasesTrackerWindow) GUITLLogicPhasesTrackerWindowMap[] = {
148 : FXMAPFUNC(SEL_CONFIGURE, 0, GUITLLogicPhasesTrackerWindow::onConfigure),
149 : FXMAPFUNC(SEL_PAINT, 0, GUITLLogicPhasesTrackerWindow::onPaint),
150 : FXMAPFUNC(SEL_COMMAND, MID_SIMSTEP, GUITLLogicPhasesTrackerWindow::onSimStep),
151 :
152 : };
153 :
154 0 : FXIMPLEMENT(GUITLLogicPhasesTrackerWindow, FXMainWindow, GUITLLogicPhasesTrackerWindowMap, ARRAYNUMBER(GUITLLogicPhasesTrackerWindowMap))
155 :
156 :
157 : /* -------------------------------------------------------------------------
158 : * GUITLLogicPhasesTrackerWindow-methods
159 : * ----------------------------------------------------------------------- */
160 0 : GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerWindow(
161 : GUIMainWindow& app,
162 : MSTrafficLightLogic& logic, GUITrafficLightLogicWrapper& wrapper,
163 0 : ValueSource<std::pair<SUMOTime, MSPhaseDefinition> >* src) :
164 : FXMainWindow(app.getApp(), "TLS-Tracker", nullptr, nullptr, DECOR_ALL, 20, 20, 300, 200),
165 0 : myApplication(&app),
166 0 : myTLLogic(&logic),
167 0 : myAmInTrackingMode(true) {
168 0 : initToolBar();
169 0 : myConnector = new GLObjectValuePassConnector<std::pair<SUMOTime, MSPhaseDefinition> >(wrapper, src, this);
170 0 : app.addChild(this);
171 0 : for (int i = 0; i < (int)myTLLogic->getLinks().size(); ++i) {
172 0 : myLinkNames.push_back(toString<int>(i));
173 : }
174 0 : for (auto item : myTLLogic->getDetectorStates()) {
175 : std::string detID = item.first;
176 0 : if (detID.size() > 4) {
177 0 : detID = detID.substr(detID.size() - 4);
178 : }
179 0 : myDetectorNames.push_back(detID);
180 : }
181 0 : for (auto item : myTLLogic->getConditions()) {
182 0 : myConditionNames.push_back(item.first);
183 : }
184 0 : loadSettings();
185 0 : const int newHeight = computeHeight();
186 0 : FXScrollWindow* scrollWindow = new FXScrollWindow(this, LAYOUT_FILL_X | LAYOUT_FILL_Y | HSCROLLER_NEVER | FRAME_NONE);
187 0 : FXHorizontalFrame* spacerFrame = new FXHorizontalFrame(scrollWindow, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y | FRAME_NONE);
188 0 : new FXScrollWindow(spacerFrame, LAYOUT_FIX_WIDTH | LAYOUT_FIX_HEIGHT | FRAME_NONE, 0, 0, 0, newHeight - 40);
189 : FXVerticalFrame* glcanvasFrame =
190 : new FXVerticalFrame(spacerFrame,
191 : FRAME_SUNKEN | LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y,
192 0 : 0, 0, 0, 0, 0, 0, 0, 0);
193 0 : myPanel = new GUITLLogicPhasesTrackerPanel(glcanvasFrame, *myApplication, *this);
194 0 : setTitle((logic.getID() + " - " + logic.getProgramID() + " - tracker").c_str());
195 0 : setIcon(GUIIconSubSys::getIcon(GUIIcon::APP_TLSTRACKER));
196 0 : setHeight(newHeight);
197 0 : }
198 :
199 :
200 0 : GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerWindow(
201 : GUIMainWindow& app,
202 : MSTrafficLightLogic& logic, GUITrafficLightLogicWrapper& /*wrapper*/,
203 0 : const MSSimpleTrafficLightLogic::Phases& /*phases*/) :
204 : FXMainWindow(app.getApp(), "TLS-Tracker", nullptr, nullptr, DECOR_ALL, 20, 20, 300, 200),
205 0 : myApplication(&app),
206 0 : myTLLogic(&logic),
207 0 : myAmInTrackingMode(false),
208 0 : myToolBarDrag(nullptr),
209 0 : myBeginOffset(nullptr) {
210 0 : myConnector = nullptr;
211 0 : initToolBar();
212 0 : app.addChild(this);
213 0 : for (int i = 0; i < (int)myTLLogic->getLinks().size(); ++i) {
214 0 : myLinkNames.push_back(toString<int>(i));
215 : }
216 0 : int newHeight = computeHeight();
217 0 : FXScrollWindow* scrollWindow = new FXScrollWindow(this, LAYOUT_FILL_X | LAYOUT_FILL_Y | HSCROLLER_NEVER | FRAME_NONE);
218 0 : FXHorizontalFrame* spacerFrame = new FXHorizontalFrame(scrollWindow, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y | FRAME_NONE);
219 0 : new FXScrollWindow(spacerFrame, LAYOUT_FIX_WIDTH | LAYOUT_FIX_HEIGHT | FRAME_NONE, 0, 0, 0, newHeight - 40);
220 : FXVerticalFrame* glcanvasFrame =
221 : new FXVerticalFrame(spacerFrame,
222 : FRAME_SUNKEN | LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y,
223 0 : 0, 0, 0, 0, 0, 0, 0, 0);
224 0 : myPanel = new GUITLLogicPhasesTrackerPanel(glcanvasFrame, *myApplication, *this);
225 0 : setTitle((logic.getID() + " - " + logic.getProgramID() + " - phases").c_str());
226 0 : setIcon(GUIIconSubSys::getIcon(GUIIcon::APP_TLSTRACKER));
227 0 : setHeight(newHeight);
228 0 : setWidth(700);
229 0 : }
230 :
231 :
232 0 : GUITLLogicPhasesTrackerWindow::~GUITLLogicPhasesTrackerWindow() {
233 0 : if (myAmInTrackingMode) {
234 0 : saveSettings();
235 0 : myLastY = -1;
236 : }
237 0 : myApplication->removeChild(this);
238 0 : delete myConnector;
239 : // just to quit cleanly on a failure
240 0 : if (myLock.locked()) {
241 0 : myLock.unlock();
242 : }
243 0 : delete myToolBarDrag;
244 0 : }
245 :
246 : void
247 0 : GUITLLogicPhasesTrackerWindow::initToolBar() {
248 0 : myToolBarDrag = new FXToolBarShell(this, GUIDesignToolBar);
249 0 : myToolBar = new FXToolBar(this, myToolBarDrag, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | FRAME_RAISED);
250 0 : new FXToolBarGrip(myToolBar, myToolBar, FXToolBar::ID_TOOLBARGRIP, GUIDesignToolBarGrip);
251 :
252 0 : if (myAmInTrackingMode) {
253 : // interval manipulation
254 0 : new FXLabel(myToolBar, "range (s):", nullptr, LAYOUT_CENTER_Y);
255 0 : myBeginOffset = new FXRealSpinner(myToolBar, 4, this, MID_SIMSTEP, LAYOUT_TOP | FRAME_SUNKEN | FRAME_THICK);
256 : //myBeginOffset->setFormatString("%.0f");
257 : //myBeginOffset->setIncrements(1, 10, 100);
258 0 : myBeginOffset->setIncrement(10);
259 0 : myBeginOffset->setRange(60, 3600);
260 0 : myBeginOffset->setValue(240);
261 : }
262 :
263 0 : new FXLabel(myToolBar, "time style:", nullptr, LAYOUT_CENTER_Y);
264 0 : myTimeMode = new MFXComboBoxIcon(myToolBar, 11, false, GUIDesignComboBoxVisibleItemsMedium,
265 0 : this, MID_SIMSTEP, GUIDesignViewSettingsComboBox1);
266 0 : myTimeMode->appendIconItem("seconds");
267 0 : myTimeMode->appendIconItem("MM:SS");
268 0 : myTimeMode->appendIconItem("time in cycle");
269 :
270 0 : new FXLabel(myToolBar, "green time", nullptr, LAYOUT_CENTER_Y);
271 0 : myGreenMode = new MFXComboBoxIcon(myToolBar, 6, false, GUIDesignComboBoxVisibleItemsMedium,
272 0 : this, MID_SIMSTEP, GUIDesignViewSettingsComboBox1);
273 0 : myGreenMode->appendIconItem("off");
274 0 : myGreenMode->appendIconItem("phase");
275 0 : myGreenMode->appendIconItem("running");
276 :
277 0 : myIndexMode = new FXCheckButton(myToolBar, TL("phase names"), this, MID_SIMSTEP);
278 :
279 0 : if (myAmInTrackingMode) {
280 0 : myDetectorMode = new FXCheckButton(myToolBar, TL("detectors"), this, MID_SIMSTEP);
281 0 : myConditionMode = new FXCheckButton(myToolBar, TL("conditions"), this, MID_SIMSTEP);
282 : } else {
283 0 : myDetectorMode = nullptr;
284 0 : myConditionMode = nullptr;
285 : }
286 0 : }
287 :
288 :
289 : void
290 0 : GUITLLogicPhasesTrackerWindow::create() {
291 0 : FXMainWindow::create();
292 0 : if (myToolBarDrag != nullptr) {
293 0 : myToolBarDrag->create();
294 : }
295 0 : }
296 :
297 : int
298 0 : GUITLLogicPhasesTrackerWindow::computeHeight() {
299 0 : int newHeight = (int)myTLLogic->getLinks().size() * 20 + 30 + 8 + 30 + 60;
300 0 : if (myAmInTrackingMode) {
301 : newHeight += 20; // time bar
302 0 : newHeight += 10; // something extra caused by the scroll frames
303 0 : if (myDetectorMode->getCheck()) {
304 0 : newHeight += (int)myTLLogic->getDetectorStates().size() * 20 + 5;
305 : }
306 0 : if (myConditionMode->getCheck()) {
307 0 : newHeight += (int)myTLLogic->getConditions().size() * 20 + 5;
308 : }
309 : }
310 0 : return newHeight;
311 : }
312 :
313 : void
314 0 : GUITLLogicPhasesTrackerWindow::drawValues(GUITLLogicPhasesTrackerPanel& caller) {
315 : // compute what shall be shown (what is visible)
316 0 : myFirstPhase2Show = 0;
317 0 : myFirstPhaseOffset = 0;
318 : SUMOTime leftOffset = 0;
319 0 : myFirstDet2Show = 0;
320 0 : myFirstDetOffset = 0;
321 0 : myFirstCond2Show = 0;
322 0 : myFirstCondOffset = 0;
323 0 : myFirstTime2Show = 0;
324 0 : if (!myAmInTrackingMode) {
325 : myPhases.clear();
326 : myDurations.clear();
327 : myTimeInCycle.clear();
328 : myPhaseIndex.clear();
329 : // insert phases
330 0 : MSSimpleTrafficLightLogic* simpleTLLogic = dynamic_cast<MSSimpleTrafficLightLogic*>(myTLLogic);
331 0 : if (simpleTLLogic == nullptr) {
332 0 : return;
333 : }
334 0 : myLastTime = 0;
335 0 : myBeginTime = 0;
336 : int idx = 0;
337 0 : for (MSPhaseDefinition* const phase : simpleTLLogic->getPhases()) {
338 0 : myPhases.push_back(*phase);
339 0 : myDurations.push_back(phase->duration);
340 0 : myTimeInCycle.push_back(myLastTime);
341 0 : myPhaseIndex.push_back(idx++);
342 0 : myLastTime += phase->duration;
343 : }
344 0 : if (myLastTime <= myBeginTime) {
345 0 : WRITE_ERROR(TL("Overflow in time computation occurred."));
346 0 : return;
347 : }
348 : } else {
349 0 : SUMOTime beginOffset = TIME2STEPS(myBeginOffset->getValue());
350 0 : myBeginTime = myLastTime - beginOffset;
351 0 : myFirstTime2Show = myBeginTime;
352 : // check whether no phases are known at all
353 0 : if (myDurations.size() != 0) {
354 : SUMOTime durs = 0;
355 0 : int phaseOffset = (int)myDurations.size() - 1;
356 : DurationsVector::reverse_iterator i = myDurations.rbegin();
357 0 : while (i != myDurations.rend()) {
358 0 : if (durs + (*i) > beginOffset) {
359 0 : myFirstPhase2Show = phaseOffset;
360 0 : myFirstPhaseOffset = (durs + (*i)) - beginOffset;
361 0 : break;
362 : }
363 : durs += (*i);
364 0 : phaseOffset--;
365 : ++i;
366 : }
367 0 : if (i == myDurations.rend()) {
368 : // there are too few information stored;
369 0 : myFirstPhase2Show = 0;
370 0 : myFirstPhaseOffset = 0;
371 0 : leftOffset = beginOffset - durs;
372 : }
373 : }
374 0 : if (myDetectorDurations.size() != 0) {
375 : SUMOTime durs = 0;
376 0 : int phaseOffset = (int)myDetectorDurations.size() - 1;
377 : DurationsVector::reverse_iterator i = myDetectorDurations.rbegin();
378 0 : while (i != myDetectorDurations.rend()) {
379 0 : if (durs + (*i) > beginOffset) {
380 0 : myFirstDet2Show = phaseOffset;
381 0 : myFirstDetOffset = (durs + (*i)) - beginOffset;
382 0 : break;
383 : }
384 : durs += (*i);
385 0 : phaseOffset--;
386 : ++i;
387 : }
388 0 : if (i == myDetectorDurations.rend()) {
389 : // there are too few information stored;
390 0 : myFirstDet2Show = 0;
391 0 : myFirstDetOffset = 0;
392 : }
393 : }
394 0 : if (myConditionDurations.size() != 0) {
395 : SUMOTime durs = 0;
396 0 : int phaseOffset = (int)myConditionDurations.size() - 1;
397 : DurationsVector::reverse_iterator i = myConditionDurations.rbegin();
398 0 : while (i != myConditionDurations.rend()) {
399 0 : if (durs + (*i) > beginOffset) {
400 0 : myFirstCond2Show = phaseOffset;
401 0 : myFirstCondOffset = (durs + (*i)) - beginOffset;
402 0 : break;
403 : }
404 : durs += (*i);
405 0 : phaseOffset--;
406 : ++i;
407 : }
408 0 : if (i == myConditionDurations.rend()) {
409 : // there are too few information stored;
410 0 : myFirstCond2Show = 0;
411 0 : myFirstCondOffset = 0;
412 : }
413 : }
414 : }
415 : // begin drawing
416 0 : glMatrixMode(GL_PROJECTION);
417 0 : glLoadIdentity();
418 0 : glMatrixMode(GL_MODELVIEW);
419 0 : glLoadIdentity();
420 0 : glTranslated(-1, -1, 0);
421 0 : glScaled(2, 2, 1);
422 0 : glDisable(GL_TEXTURE_2D);
423 : // draw the horizontal lines dividing the signal groups
424 0 : glColor3d(1, 1, 1);
425 : // compute some values needed more than once
426 0 : const double panelHeight = (double) caller.getHeight();
427 0 : const double panelWidth = (double) caller.getWidth();
428 0 : const double barWidth = MAX2(1.0, panelWidth - 31);
429 0 : const double fontHeight = 0.06 * 300. / panelHeight;
430 0 : const double fontWidth = 0.06 * 300. / panelWidth;
431 0 : const double h9 = 9. / panelHeight;
432 0 : const double hTop = 20. / panelHeight;
433 0 : const double h11 = 11. / panelHeight;
434 0 : const double stateHeight = 16. / panelHeight;
435 : const double h20 = 20. / panelHeight;
436 0 : const double h30 = 15. / panelHeight;
437 0 : const double h35 = 34. / panelHeight;
438 0 : const double h60 = 70. / panelHeight;
439 0 : const double h75 = 73. / panelHeight;
440 0 : const double h80 = 90. / panelHeight;
441 0 : const double w30 = 30 / panelWidth;
442 0 : double h = 1. - hTop;
443 : // draw the line below indices
444 0 : glColor3d(1, 1, 1);
445 0 : glBegin(GL_LINES);
446 0 : glVertex2d(0, h);
447 0 : glVertex2d(1, h);
448 0 : glEnd();
449 : // draw the link names and the lines dividing them
450 0 : drawNames(myLinkNames, fontHeight, fontWidth, h20, w30, h, 0);
451 0 : glBegin(GL_LINES);
452 0 : glVertex2d(0, h + h20);
453 0 : glVertex2d(1.0, h + h20);
454 0 : glEnd();
455 :
456 : // draw the names closure (vertical line)
457 0 : h += h20;
458 0 : glColor3d(1, 1, 1);
459 0 : glBegin(GL_LINES);
460 0 : glVertex2d(w30, 1.);
461 0 : glVertex2d(w30, h);
462 0 : glEnd();
463 :
464 0 : if (myAmInTrackingMode) {
465 : // optionally draw detector names
466 0 : h -= h60;
467 0 : if (myDetectorMode->getCheck()) {
468 : const double top = h;
469 0 : glBegin(GL_LINES);
470 0 : glVertex2d(0, h);
471 0 : glVertex2d(1.0, h);
472 0 : glEnd();
473 0 : drawNames(myDetectorNames, fontHeight * 0.7, fontWidth * 0.7, h20, w30, h, 3);
474 0 : glBegin(GL_LINES);
475 0 : glVertex2d(0, h + h20);
476 0 : glVertex2d(1.0, h + h20);
477 0 : glEnd();
478 : // draw the names closure (vertical line)
479 0 : glColor3d(1, 1, 1);
480 0 : glBegin(GL_LINES);
481 0 : glVertex2d(30. / panelWidth, top);
482 0 : glVertex2d(30. / panelWidth, h + h20);
483 0 : glEnd();
484 0 : h -= h30;
485 : }
486 : // optionally draw condition names
487 0 : if (myConditionMode->getCheck()) {
488 0 : const double top = h;
489 0 : glBegin(GL_LINES);
490 0 : glVertex2d(0, h);
491 0 : glVertex2d(1.0, h);
492 0 : glEnd();
493 0 : drawNames(myConditionNames, fontHeight * 0.7, fontWidth * 0.7, h20, w30, h, 3);
494 0 : glBegin(GL_LINES);
495 0 : glVertex2d(0, h + h20);
496 0 : glVertex2d(1.0, h + h20);
497 0 : glEnd();
498 : // draw the names closure (vertical line)
499 0 : glColor3d(1, 1, 1);
500 0 : glBegin(GL_LINES);
501 0 : glVertex2d(30. / panelWidth, top);
502 0 : glVertex2d(30. / panelWidth, h + h20);
503 0 : glEnd();
504 : }
505 : }
506 :
507 : // draw the phases
508 : // disable value addition while drawing
509 0 : myLock.lock();
510 : // determine the initial offset
511 0 : double x = 31. / panelWidth;
512 0 : double ta = (double) leftOffset / panelWidth;
513 0 : ta *= barWidth / ((double)(myLastTime - myBeginTime));
514 0 : x += ta;
515 :
516 : // and the initial phase information
517 0 : PhasesVector::iterator pi = myPhases.begin() + myFirstPhase2Show;
518 : IndexVector::iterator ii = myPhaseIndex.begin() + myFirstPhase2Show;
519 :
520 0 : SUMOTime fpo = myFirstPhaseOffset;
521 0 : const bool phaseNames = myIndexMode->getCheck() == TRUE;
522 0 : std::string lastName = "";
523 : double spaceForName = 0;
524 :
525 : // start drawing
526 0 : std::vector<SUMOTime> runningGreen(myTLLogic->getLinks().size(), 0);
527 0 : for (DurationsVector::iterator pd = myDurations.begin() + myFirstPhase2Show; pd != myDurations.end(); ++pd) {
528 : // the first phase may be drawn incompletely
529 0 : SUMOTime duration = *pd - fpo;
530 : // compute the height and the width of the phase
531 0 : h = 1. - hTop;
532 0 : double a = (double) duration / panelWidth;
533 0 : a *= barWidth / ((double)(myLastTime - myBeginTime));
534 0 : const double x2 = x + a;
535 :
536 : // go through the links
537 0 : for (int j = 0; j < (int) myTLLogic->getLinks().size(); ++j) {
538 : // determine the current link's color
539 0 : LinkState state = pi->getSignalState(j);
540 : // draw the bar (red is drawn as a line)
541 0 : GLHelper::setColor(GUIVisualizationSettings::getLinkColor(state));
542 0 : switch (state) {
543 0 : case LINKSTATE_TL_RED:
544 : case LINKSTATE_TL_REDYELLOW:
545 : // draw a thin line
546 0 : glBegin(GL_QUADS);
547 0 : glVertex2d(x, h - h11);
548 0 : glVertex2d(x, h - h9);
549 0 : glVertex2d(x2, h - h9);
550 0 : glVertex2d(x2, h - h11);
551 0 : glEnd();
552 : break;
553 0 : default:
554 : // draw a thick block
555 0 : glBegin(GL_QUADS);
556 0 : glVertex2d(x, h - stateHeight);
557 0 : glVertex2d(x, h);
558 0 : glVertex2d(x2, h);
559 0 : glVertex2d(x2, h - stateHeight);
560 0 : glEnd();
561 : break;
562 : }
563 0 : if (myGreenMode->getCurrentItem() != 0) {
564 : SUMOTime drawnDuration = 0;
565 : double xOffset = 0;
566 0 : if (state == LINKSTATE_TL_GREEN_MINOR || state == LINKSTATE_TL_GREEN_MAJOR) {
567 0 : if (myGreenMode->getCurrentItem() == 1) {
568 0 : drawnDuration = *pd;
569 : } else {
570 0 : runningGreen[j] += *pd;
571 0 : if (pd + 1 == myDurations.end()) {
572 : drawnDuration = runningGreen[j];
573 0 : xOffset = -(double)(drawnDuration - *pd) / panelWidth * (barWidth / ((double)(myLastTime - myBeginTime)));
574 : }
575 : }
576 : } else {
577 0 : if (runningGreen[j] > 0) {
578 : drawnDuration = runningGreen[j];
579 0 : xOffset = -(double)drawnDuration / panelWidth * (barWidth / ((double)(myLastTime - myBeginTime)));
580 : }
581 0 : runningGreen[j] = 0;
582 : }
583 0 : if (drawnDuration > 0) {
584 0 : GLHelper::drawText(toString((int)STEPS2TIME(drawnDuration)),
585 0 : Position(x + xOffset, h - h9),
586 : 0, fontHeight, RGBColor::BLACK, 0, FONS_ALIGN_LEFT | FONS_ALIGN_MIDDLE, fontWidth);
587 : }
588 : }
589 : // proceed to next link
590 0 : h -= h20;
591 : }
592 :
593 : // draw phase index / name (no names for intermediate)
594 0 : std::string name = phaseNames ? pi->getName() : toString(*ii);
595 0 : if (name != lastName) {
596 0 : const double lastNameWidth = GLHelper::getTextWidth(lastName, fontWidth);
597 0 : if (spaceForName < lastNameWidth) {
598 : // clear space to avoid overdrawn text
599 0 : glColor3d(0, 0, 0);
600 0 : glBegin(GL_QUADS);
601 0 : glVertex2d(x, 1 - fontHeight);
602 0 : glVertex2d(x, 1);
603 0 : glVertex2d(1, 1);
604 0 : glVertex2d(1, 1 - fontHeight);
605 0 : glEnd();
606 : }
607 : spaceForName = a;
608 0 : GLHelper::drawText(name, Position(x, 1 - hTop), 0, fontHeight, RGBColor::WHITE, 0, FONS_ALIGN_LEFT | FONS_ALIGN_BOTTOM, fontWidth);
609 : } else {
610 0 : spaceForName += a;
611 : }
612 : lastName = name;
613 : // proceed to next phase
614 : ++pi;
615 : ++ii;
616 : x = x2;
617 : // all further phases are drawn in full
618 : fpo = 0;
619 : }
620 :
621 0 : if (myAmInTrackingMode) {
622 0 : h -= h75;
623 0 : if (myDetectorMode->getCheck()) {
624 0 : glColor3d(0.7, 0.7, 1.0);
625 0 : drawAdditionalStates(caller, myDetectorStates, myDetectorDurations, myFirstDetOffset, myFirstDet2Show, h,
626 : panelWidth, (double)leftOffset, barWidth, stateHeight, h20, h);
627 0 : h -= h35;
628 : }
629 0 : if (myConditionMode->getCheck()) {
630 0 : glColor3d(0.9, 0.6, 0.9);
631 0 : drawAdditionalStates(caller, myConditionStates, myConditionDurations, myFirstCondOffset, myFirstCond2Show, h,
632 : panelWidth, (double)leftOffset, barWidth, stateHeight, h20, h);
633 : }
634 : }
635 : // allow value addition
636 0 : myLock.unlock();
637 :
638 0 : if (myPhases.size() != 0) {
639 0 : const double timeRange = STEPS2TIME(myLastTime - myBeginTime);
640 : SUMOTime tickDist = TIME2STEPS(10);
641 : // patch distances - hack
642 0 : double t = myBeginOffset != nullptr ? myBeginOffset->getValue() : timeRange;
643 0 : while (t > barWidth / 4.) {
644 : tickDist += TIME2STEPS(10);
645 0 : t -= barWidth / 4.;
646 : }
647 : // draw time information
648 : //h = (double)(myTLLogic->getLinks().size() * 20 + 12);
649 0 : double glh = 1. - (double)myTLLogic->getLinks().size() * h20 - hTop;
650 : // current begin time
651 : // time ticks
652 0 : SUMOTime currTime = myFirstTime2Show;
653 : double glpos = 31. / panelWidth;
654 0 : const double ticSize = 4. / panelHeight;
655 0 : if (leftOffset > 0) {
656 0 : const double a = STEPS2TIME(leftOffset) * barWidth / timeRange;
657 0 : glpos += a / panelWidth;
658 0 : currTime += leftOffset;
659 0 : } else if (myFirstPhaseOffset > 0) {
660 0 : const double a = STEPS2TIME(-myFirstPhaseOffset) * barWidth / timeRange;
661 0 : glpos += a / panelWidth;
662 0 : currTime -= myFirstPhaseOffset;
663 : }
664 0 : int ticShift = myFirstPhase2Show;
665 0 : const bool mmSS = myTimeMode->getCurrentItem() == 1;
666 0 : const bool cycleTime = myTimeMode->getCurrentItem() == 2;
667 : SUMOTime lastTimeInCycle = -1;
668 : lastName = "";
669 0 : pi = myPhases.begin() + myFirstPhase2Show;
670 0 : for (DurationsVector::iterator pd = myDurations.begin() + myFirstPhase2Show; pd != myDurations.end(); ++pd) {
671 0 : const SUMOTime timeInCycle = myTimeInCycle[pd - myDurations.begin()];
672 : // draw times at different heights
673 0 : ticShift = (ticShift % 3) + 1;
674 : const std::string timeStr = (mmSS
675 0 : ? StringUtils::padFront(toString((currTime % 3600000) / 60000), 2, '0') + ":"
676 0 : + StringUtils::padFront(toString((currTime % 60000) / 1000), 2, '0')
677 0 : : toString((int)STEPS2TIME(cycleTime ? timeInCycle : currTime)));
678 0 : const double w = 10 * (double)timeStr.size() / panelWidth;
679 0 : glTranslated(glpos - w / 2., glh - h20 * ticShift, 0);
680 0 : GLHelper::drawText(timeStr, Position(0, 0), 1, fontHeight, RGBColor::WHITE, 0, FONS_ALIGN_LEFT | FONS_ALIGN_MIDDLE, fontWidth);
681 0 : glTranslated(-glpos + w / 2., -glh + h20 * ticShift, 0);
682 :
683 : // draw tic
684 0 : glColor3d(1, 1, 1);
685 0 : glBegin(GL_LINES);
686 0 : glVertex2d(glpos, glh);
687 0 : glVertex2d(glpos, glh - ticSize * ticShift);
688 0 : glEnd();
689 :
690 : // draw vertical lines for names, detectors and conditions on each phase switch
691 0 : if (myAmInTrackingMode) {
692 : double hStart = 1;
693 0 : if (!phaseNames || (pi->getName() != lastName)) {
694 0 : glColor3d(0.4, 0.4, 0.4);
695 0 : glBegin(GL_LINES);
696 0 : glVertex2d(glpos, hStart);
697 : hStart -= h20;
698 0 : glVertex2d(glpos, hStart);
699 0 : glEnd();
700 : }
701 : lastName = pi->getName();
702 :
703 0 : hStart = glh - h60;
704 0 : if (myDetectorMode->getCheck() && glpos >= w30) {
705 0 : glColor3d(0.4, 0.4, 0.4);
706 0 : glBegin(GL_LINES);
707 0 : glVertex2d(glpos, hStart);
708 0 : hStart -= (double)myDetectorNames.size() * h20;
709 0 : glVertex2d(glpos, hStart);
710 0 : glEnd();
711 0 : hStart -= h35;
712 : }
713 0 : if (myConditionMode->getCheck() && glpos >= w30) {
714 0 : glColor3d(0.4, 0.4, 0.4);
715 0 : glBegin(GL_LINES);
716 0 : glVertex2d(glpos, hStart);
717 0 : glVertex2d(glpos, hStart - (double)myConditionNames.size() * h20);
718 0 : glEnd();
719 : }
720 : }
721 :
722 : // draw vertical line for cycle reset
723 0 : if (timeInCycle == 0 || timeInCycle < lastTimeInCycle) {
724 0 : const double cycle0pos = glpos - STEPS2TIME(timeInCycle) * barWidth / timeRange / panelWidth;
725 0 : if (cycle0pos >= 31 / panelWidth) {
726 0 : glColor3d(0.6, 0.6, 0.6);
727 0 : glBegin(GL_LINES);
728 0 : glVertex2d(cycle0pos, 1);
729 0 : glVertex2d(cycle0pos, glh);
730 0 : glEnd();
731 0 : glColor3d(1, 1, 1);
732 : }
733 : }
734 :
735 : lastTimeInCycle = timeInCycle;
736 0 : tickDist = *pd;
737 0 : const double a = STEPS2TIME(tickDist) * barWidth / timeRange;
738 0 : glpos += a / panelWidth;
739 0 : currTime += tickDist;
740 : ++pi;
741 : }
742 :
743 : // draw bottom time bar with fixed spacing
744 0 : if (myAmInTrackingMode && (myDetectorMode->getCheck() || myConditionMode->getCheck()) && glpos >= w30) {
745 0 : glColor3d(1, 1, 1);
746 : tickDist = TIME2STEPS(10);
747 : // patch distances - hack
748 0 : t = myBeginOffset != nullptr ? myBeginOffset->getValue() : STEPS2TIME(myLastTime - myBeginTime);
749 0 : while (t > barWidth / 4.) {
750 0 : tickDist += TIME2STEPS(10);
751 0 : t -= barWidth / 4.;
752 : }
753 0 : glh = 1. - (double)myLinkNames.size() * h20 - h80;
754 0 : glh -= h20 * (double)(myDetectorMode->getCheck() ? myDetectorNames.size() : myConditionNames.size());
755 0 : currTime = myFirstTime2Show;
756 : int pos = 31;
757 : glpos = (double) pos / panelWidth;
758 0 : if (leftOffset > 0) {
759 0 : const double a = STEPS2TIME(leftOffset) * barWidth / timeRange;
760 0 : pos += (int)a;
761 0 : glpos += a / panelWidth;
762 0 : currTime += leftOffset;
763 0 : } else if (myFirstPhaseOffset > 0) {
764 0 : const double a = -STEPS2TIME(myBeginTime % tickDist) * barWidth / timeRange;
765 0 : pos += (int)a;
766 0 : glpos += a / panelWidth;
767 0 : currTime = myBeginTime - (myBeginTime % tickDist);
768 : }
769 0 : while (pos < panelWidth + 50.) {
770 : const std::string timeStr = (mmSS
771 0 : ? StringUtils::padFront(toString((currTime % 3600000) / 60000), 2, '0') + ":"
772 0 : + StringUtils::padFront(toString((currTime % 60000) / 1000), 2, '0')
773 0 : : toString((int)STEPS2TIME(cycleTime ? findTimeInCycle(currTime) : currTime)));
774 0 : const double w = 10. * (double)timeStr.size() / panelWidth;
775 0 : glTranslated(glpos - w / 2., glh - h20, 0);
776 0 : GLHelper::drawText(timeStr, Position(0, 0), 1, fontHeight, RGBColor::WHITE, 0, FONS_ALIGN_LEFT | FONS_ALIGN_MIDDLE, fontWidth);
777 0 : glTranslated(-glpos + w / 2., -glh + h20, 0);
778 :
779 0 : glBegin(GL_LINES);
780 0 : glVertex2d(glpos, glh);
781 0 : glVertex2d(glpos, glh - ticSize);
782 0 : glEnd();
783 :
784 0 : const double a = STEPS2TIME(tickDist) * barWidth / STEPS2TIME(myLastTime - myBeginTime);
785 0 : pos += (int) a;
786 0 : glpos += a / panelWidth;
787 0 : currTime += tickDist;
788 : }
789 : }
790 : }
791 0 : }
792 :
793 :
794 : void
795 0 : GUITLLogicPhasesTrackerWindow::drawNames(const std::vector<std::string>& names, double fontHeight, double fontWidth, double divHeight, double divWidth, double& h, int extraLines) {
796 : int i = 0;
797 0 : for (const std::string& name : names) {
798 : // draw the bar
799 0 : glBegin(GL_LINES);
800 0 : glVertex2d(0, h);
801 0 : glVertex2d(divWidth, h);
802 0 : glEnd();
803 : // draw the name
804 0 : glTranslated(0, h - divHeight, 0);
805 0 : GLHelper::drawText(name, Position(0, 0), 1, fontHeight, RGBColor::WHITE, 0, FONS_ALIGN_LEFT | FONS_ALIGN_BOTTOM, fontWidth);
806 0 : glTranslated(0, -h + divHeight, 0);
807 :
808 0 : if (extraLines > 0 && i > 0 && i % extraLines == 0) {
809 0 : glColor3d(0.4, 0.4, 0.4);
810 0 : glBegin(GL_LINES);
811 0 : glVertex2d(divWidth, h);
812 0 : glVertex2d(1.0, h);
813 0 : glEnd();
814 0 : glColor3d(1, 1, 1);
815 : }
816 0 : h -= divHeight;
817 0 : i++;
818 : }
819 0 : h -= divHeight;
820 0 : }
821 :
822 :
823 : void
824 0 : GUITLLogicPhasesTrackerWindow::drawAdditionalStates(GUITLLogicPhasesTrackerPanel& caller,
825 : const AdditionalStatesVector& states,
826 : const DurationsVector& durations, SUMOTime firstOffset, int first2Show, double hStart,
827 : double panelWidth, double leftOffset, double barWidth, double stateHeight, double h20, double& h) {
828 0 : double x = 31. / panelWidth;
829 0 : double ta = leftOffset / panelWidth;
830 0 : ta *= barWidth / ((double)(myLastTime - myBeginTime));
831 0 : x += ta;
832 : auto di = states.begin() + first2Show;
833 : SUMOTime fpo = firstOffset;
834 :
835 0 : double mx = caller.getMousePos().x() / caller.getWidth();
836 0 : double my = 1 - caller.getMousePos().y() / caller.getHeight();
837 0 : std::string tooltip = "";
838 : // start drawing
839 0 : for (auto pd = durations.begin() + first2Show; pd != durations.end(); ++pd) {
840 : // the first phase may be drawn incompletely
841 0 : SUMOTime duration = *pd - fpo;
842 : // compute the height and the width of the phase
843 0 : h = hStart;
844 0 : double a = (double) duration / panelWidth;
845 0 : a *= barWidth / ((double)(myLastTime - myBeginTime));
846 0 : const double x2 = x + a;
847 0 : const bool tooltipX = x < mx && mx < x2;
848 : //std::cout << SIMTIME << " detStates=" << toString(*di) << "\n";
849 : // go through the detectors
850 0 : for (double j : *di) {
851 0 : if (j != 0) {
852 : // draw a thick block
853 0 : glBegin(GL_QUADS);
854 0 : glVertex2d(x, h - stateHeight);
855 0 : glVertex2d(x, h);
856 0 : glVertex2d(x2, h);
857 0 : glVertex2d(x2, h - stateHeight);
858 0 : glEnd();
859 0 : if (tooltipX) {
860 0 : const bool tooltipY = (h - stateHeight) < my && my < h;
861 : if (tooltipY) {
862 0 : tooltip = toString((int)j);
863 : }
864 : }
865 : }
866 : // proceed to next link
867 0 : h -= h20;
868 : }
869 : // proceed to next phase
870 : ++di;
871 : x = x2;
872 : // all further phases are drawn in full
873 : fpo = 0;
874 : }
875 0 : if (tooltip != "") {
876 : // delay tool tip drawing until all bars are drawn to prevent overwriting
877 0 : GLHelper::drawText(tooltip, Position(mx, my), 0, h20, RGBColor::YELLOW, 0, FONS_ALIGN_LEFT | FONS_ALIGN_MIDDLE, 20 / caller.getWidth());
878 : }
879 0 : }
880 :
881 : SUMOTime
882 0 : GUITLLogicPhasesTrackerWindow::findTimeInCycle(SUMOTime t) {
883 : // find latest cycle reset before t
884 0 : int i = (int)myPhases.size() - 1;
885 0 : SUMOTime lookBack = myLastTime - t - myDurations.back();
886 : //std::cout << SIMTIME << " findTimeInCycle t=" << STEPS2TIME(t)
887 : // << " last=" << STEPS2TIME(myLastTime)
888 : // << " lastDur=" << STEPS2TIME(myDurations.back())
889 : // << " lookBack=" << STEPS2TIME(lookBack)
890 : // << " i0=" << i;
891 : // look backwards through the phases until to the first cycle crossing before t
892 0 : while (lookBack > 0 && i > 1) {
893 0 : i--;
894 0 : lookBack -= myDurations[i];
895 : }
896 0 : SUMOTime timeInCycle = myTimeInCycle[i < 0 ? 0 : i];
897 : //std::cout << " iF=" << i << " lookBack2=" << STEPS2TIME(lookBack) << " tic=" << STEPS2TIME(timeInCycle) << "\n";
898 0 : if (lookBack <= 0) {
899 0 : return timeInCycle - lookBack;
900 : }
901 0 : return myTLLogic->mapTimeInCycle(t);
902 : }
903 :
904 : void
905 0 : GUITLLogicPhasesTrackerWindow::addValue(std::pair<SUMOTime, MSPhaseDefinition> def) {
906 : // do not draw while adding
907 0 : myLock.lock();
908 : // set the first time if not set before
909 0 : if (myPhases.size() == 0) {
910 0 : myBeginTime = def.first;
911 : }
912 : // append or set the phase
913 0 : if (myPhases.size() == 0 || myPhases.back() != def.second) {
914 0 : myPhases.push_back(def.second);
915 0 : myDurations.push_back(DELTA_T);
916 0 : myTimeInCycle.push_back(myTLLogic->mapTimeInCycle(def.first - DELTA_T));
917 0 : myPhaseIndex.push_back(myTLLogic->getCurrentPhaseIndex());
918 : } else {
919 0 : myDurations.back() += DELTA_T;
920 : }
921 : // updated detector states
922 : std::vector<double> detectorStates;
923 0 : for (auto item : myTLLogic->getDetectorStates()) {
924 0 : detectorStates.push_back(item.second);
925 : }
926 0 : if (myDetectorStates.size() == 0 || myDetectorStates.back() != detectorStates) {
927 0 : myDetectorStates.push_back(detectorStates);
928 0 : myDetectorDurations.push_back(DELTA_T);
929 : } else {
930 0 : myDetectorDurations.back() += DELTA_T;
931 : }
932 : // updated condition states
933 : std::vector<double> conditionStates;
934 0 : for (auto item : myTLLogic->getConditions()) {
935 0 : conditionStates.push_back(item.second);
936 : }
937 0 : if (myConditionStates.size() == 0 || myConditionStates.back() != conditionStates) {
938 0 : myConditionStates.push_back(conditionStates);
939 0 : myConditionDurations.push_back(DELTA_T);
940 : } else {
941 0 : myConditionDurations.back() += DELTA_T;
942 : }
943 : // set the last time a phase was added at
944 0 : myLastTime = def.first;
945 : // allow drawing
946 0 : myLock.unlock();
947 0 : }
948 :
949 :
950 : long
951 0 : GUITLLogicPhasesTrackerWindow::onConfigure(FXObject* sender, FXSelector sel, void* ptr) {
952 0 : myPanel->onConfigure(sender, sel, ptr);
953 0 : return FXMainWindow::onConfigure(sender, sel, ptr);
954 : }
955 :
956 :
957 : long
958 0 : GUITLLogicPhasesTrackerWindow::onPaint(FXObject* sender, FXSelector sel, void* ptr) {
959 0 : myPanel->onPaint(sender, sel, ptr);
960 0 : return FXMainWindow::onPaint(sender, sel, ptr);
961 : }
962 :
963 :
964 : long
965 0 : GUITLLogicPhasesTrackerWindow::onSimStep(FXObject* sender, FXSelector, void*) {
966 0 : if (sender == myDetectorMode || sender == myConditionMode) {
967 0 : resize(getWidth(), computeHeight());
968 : }
969 0 : update();
970 0 : return 1;
971 : }
972 :
973 :
974 : void
975 0 : GUITLLogicPhasesTrackerWindow::setBeginTime(SUMOTime time) {
976 0 : myBeginTime = time;
977 0 : }
978 :
979 :
980 : void
981 0 : GUITLLogicPhasesTrackerWindow::saveSettings() {
982 0 : getApp()->reg().writeIntEntry("TL_TRACKER", "x", getX());
983 0 : getApp()->reg().writeIntEntry("TL_TRACKER", "y", getY());
984 0 : getApp()->reg().writeIntEntry("TL_TRACKER", "width", getWidth());
985 0 : getApp()->reg().writeIntEntry("TL_TRACKER", "timeRange", (int)myBeginOffset->getValue());
986 0 : getApp()->reg().writeIntEntry("TL_TRACKER", "timeMode", myTimeMode->getCurrentItem());
987 0 : getApp()->reg().writeIntEntry("TL_TRACKER", "greenMode", (myGreenMode->getCurrentItem()));
988 0 : getApp()->reg().writeIntEntry("TL_TRACKER", "indexMode", (int)(myIndexMode->getCheck()));
989 0 : getApp()->reg().writeIntEntry("TL_TRACKER", "detectorMode", (int)(myDetectorMode->getCheck()));
990 0 : getApp()->reg().writeIntEntry("TL_TRACKER", "conditionMode", (int)(myConditionMode->getCheck()));
991 0 : }
992 :
993 :
994 : void
995 0 : GUITLLogicPhasesTrackerWindow::loadSettings() {
996 : // ensure window is visible after switching screen resolutions
997 : const FXint minSize = 400;
998 : const FXint minTitlebarHeight = 20;
999 0 : setX(MAX2(0, MIN2(getApp()->reg().readIntEntry("TL_TRACKER", "x", 150),
1000 : getApp()->getRootWindow()->getWidth() - minSize)));
1001 0 : if (myLastY == -1) {
1002 0 : myLastY = MAX2(minTitlebarHeight,
1003 : MIN2(getApp()->reg().readIntEntry("TL_TRACKER", "y", 150),
1004 : getApp()->getRootWindow()->getHeight() - minSize));
1005 : } else {
1006 0 : myLastY += getHeight() + 20;
1007 : }
1008 0 : setY(myLastY);
1009 0 : setWidth(MAX2(getApp()->reg().readIntEntry("TL_TRACKER", "width", 700), minSize));
1010 0 : myBeginOffset->setValue(getApp()->reg().readIntEntry("TL_TRACKER", "timeRange", (int)myBeginOffset->getValue()));
1011 0 : myTimeMode->setCurrentItem(getApp()->reg().readIntEntry("TL_TRACKER", "timeMode", myTimeMode->getCurrentItem()));
1012 0 : myGreenMode->setCurrentItem(getApp()->reg().readIntEntry("TL_TRACKER", "greenMode", myGreenMode->getCurrentItem()));
1013 0 : myIndexMode->setCheck((FXbool)getApp()->reg().readIntEntry("TL_TRACKER", "indexMode", (int)(myIndexMode->getCheck())));
1014 0 : myDetectorMode->setCheck((FXbool)getApp()->reg().readIntEntry("TL_TRACKER", "detectorMode", (int)(myDetectorMode->getCheck())));
1015 0 : myConditionMode->setCheck((FXbool)getApp()->reg().readIntEntry("TL_TRACKER", "conditionMode", (int)(myConditionMode->getCheck())));
1016 0 : }
1017 :
1018 : /****************************************************************************/
|