INSTINCT Code Coverage Report


Directory: src/
File: internal/gui/widgets/TimeEdit.cpp
Date: 2025-11-25 23:34:18
Exec Total Coverage
Lines: 4 82 4.9%
Functions: 1 5 20.0%
Branches: 0 136 0.0%

Line Branch Exec Source
1 // This file is part of INSTINCT, the INS Toolkit for Integrated
2 // Navigation Concepts and Training by the Institute of Navigation of
3 // the University of Stuttgart, Germany.
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
9 #include "TimeEdit.hpp"
10
11 #include <imgui.h>
12 #include <fmt/core.h>
13
14 #include "internal/gui/widgets/imgui_ex.hpp"
15 #include "internal/gui/widgets/EnumCombo.hpp"
16
17 namespace NAV
18 {
19
20 const char* to_string(gui::widgets::TimeEditFormat::Format timeEditFormat)
21 {
22 switch (timeEditFormat)
23 {
24 case gui::widgets::TimeEditFormat::Format::YMDHMS:
25 return "YMDHMS";
26 case gui::widgets::TimeEditFormat::Format::GPSWeekToW:
27 return "GPS Week/ToW";
28 case gui::widgets::TimeEditFormat::Format::COUNT:
29 break;
30 }
31 return "";
32 }
33
34 namespace gui::widgets
35 {
36 namespace
37 {
38
39 /// @brief Shows a ComboBox to select the time edit format
40 /// @param[in] label Label to show beside the combo box. This has to be a unique id for ImGui.
41 /// @param[in] format Reference to the format to select
42 bool ComboTimeEditFormat(const char* label, TimeEditFormat::Format& format)
43 {
44 return gui::widgets::EnumCombo(label, format);
45 }
46
47 } // namespace
48 } // namespace gui::widgets
49
50 } // namespace NAV
51
52 bool NAV::gui::widgets::TimeEdit(const char* str_id, InsTime& insTime, TimeEditFormat& timeEditFormat, float itemWidth, int columns)
53 {
54 bool changes = false;
55 bool edited = false;
56
57 ImGui::BeginGroup();
58
59 ImGui::SetNextItemWidth(140.0F);
60 if (ComboTimeEditFormat(fmt::format("##ComboTimeEditFormat {}", str_id).c_str(), timeEditFormat.format))
61 {
62 changes = true;
63 }
64 ImGui::SameLine();
65 ImGui::SetNextItemWidth(80.0F);
66 if (ComboTimeSystem(fmt::format("##ComboTimeSystem {}", str_id).c_str(), timeEditFormat.system))
67 {
68 changes = true;
69 }
70
71 if (timeEditFormat.format == TimeEditFormat::Format::YMDHMS)
72 {
73 auto ymdhms = insTime.toYMDHMS(timeEditFormat.system);
74
75 int year = ymdhms.year;
76 int month = ymdhms.month;
77 int day = ymdhms.day;
78 int hour = ymdhms.hour;
79 int min = ymdhms.min;
80 auto sec = static_cast<double>(ymdhms.sec);
81
82 ImGui::BeginGroup();
83 ImGui::SetNextItemWidth(itemWidth);
84 if (ImGui::InputInt(fmt::format("Year##{}", str_id).c_str(), &year, 0, 0)) { edited = true; }
85 if (ImGui::IsItemDeactivatedAfterEdit()) { changes = true; }
86
87 ImGui::SetNextItemWidth(itemWidth);
88 if (ImGui::InputIntL(fmt::format("Month##{}", str_id).c_str(), &month, 1, InsTimeUtil::MONTHS_PER_YEAR, 0, 0)) { edited = true; }
89 if (ImGui::IsItemDeactivatedAfterEdit()) { changes = true; }
90
91 ImGui::SetNextItemWidth(itemWidth);
92 if (ImGui::InputIntL(fmt::format("Day##{}", str_id).c_str(), &day, 1, InsTimeUtil::daysInMonth(month, year), 0, 0)) { edited = true; }
93 if (ImGui::IsItemDeactivatedAfterEdit()) { changes = true; }
94 ImGui::EndGroup();
95
96 if (columns == 2) { ImGui::SameLine(); }
97 ImGui::BeginGroup();
98 ImGui::SetNextItemWidth(itemWidth);
99 if (ImGui::InputIntL(fmt::format("Hour##{}", str_id).c_str(), &hour, 0, InsTimeUtil::HOURS_PER_DAY - 1, 0, 0)) { edited = true; }
100 if (ImGui::IsItemDeactivatedAfterEdit()) { changes = true; }
101
102 ImGui::SetNextItemWidth(itemWidth);
103 if (ImGui::InputIntL(fmt::format("Min##{}", str_id).c_str(), &min, 0, InsTimeUtil::MINUTES_PER_HOUR - 1, 0, 0)) { edited = true; }
104 if (ImGui::IsItemDeactivatedAfterEdit()) { changes = true; }
105
106 ImGui::SetNextItemWidth(itemWidth);
107 if (ImGui::InputDoubleL(fmt::format("Sec##{}", str_id).c_str(), &sec, 0, InsTimeUtil::SECONDS_PER_MINUTE - 1e-5, 0, 0, "%.6f")) { edited = true; }
108 if (ImGui::IsItemDeactivatedAfterEdit()) { changes = true; }
109 ImGui::EndGroup();
110
111 if (changes || edited)
112 {
113 insTime = InsTime{ static_cast<uint16_t>(year), static_cast<uint16_t>(month), static_cast<uint16_t>(day),
114 static_cast<uint16_t>(hour), static_cast<uint16_t>(min), sec, timeEditFormat.system };
115 }
116 }
117 else // if (timeEditFormat == TimeEditFormat::Format::GPSWeekToW)
118 {
119 auto gpsWeekTow = insTime.toGPSweekTow(timeEditFormat.system);
120
121 int cycle = gpsWeekTow.gpsCycle;
122 int week = gpsWeekTow.gpsWeek;
123 auto tow = static_cast<double>(gpsWeekTow.tow);
124
125 ImGui::SetNextItemWidth(itemWidth);
126 if (ImGui::InputIntL(fmt::format("Cycle##{}", str_id).c_str(), &cycle, 0, std::numeric_limits<int>::max(), 0, 0)) { edited = true; }
127 if (ImGui::IsItemDeactivatedAfterEdit()) { changes = true; }
128
129 ImGui::SetNextItemWidth(itemWidth);
130 if (ImGui::InputIntL(fmt::format("Week##{}", str_id).c_str(), &week, 0, InsTimeUtil::WEEKS_PER_GPS_CYCLE - 1, 0, 0)) { edited = true; }
131 if (ImGui::IsItemDeactivatedAfterEdit()) { changes = true; }
132
133 ImGui::SetNextItemWidth(itemWidth);
134 if (ImGui::InputDoubleL(fmt::format("ToW [s]##{}", str_id).c_str(), &tow, 0, std::numeric_limits<double>::max(), 0, 0, "%.6f")) { edited = true; }
135 if (ImGui::IsItemDeactivatedAfterEdit()) { changes = true; }
136
137 if (changes || edited)
138 {
139 insTime = InsTime{ cycle, week, tow, timeEditFormat.system };
140 }
141 }
142
143 ImGui::EndGroup();
144
145 return changes;
146 }
147
148 void NAV::gui::widgets::to_json(json& j, const TimeEditFormat& timeEditFormat)
149 {
150 j = json{
151 { "format", timeEditFormat.format },
152 { "system", timeEditFormat.system },
153 };
154 }
155
156 12 void NAV::gui::widgets::from_json(const json& j, TimeEditFormat& timeEditFormat)
157 {
158 12 j.at("format").get_to(timeEditFormat.format);
159 12 j.at("system").get_to(timeEditFormat.system);
160 12 }
161