blob: 4a60f79b9af03d1c57b7b401b1f675e57e5da422 [file] [log] [blame]
James Kuszmaulb13e13f2023-11-22 20:44:04 -08001// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5#include <cstdio>
6
7#ifndef RUNNING_SYSID_TESTS
8
9#include <filesystem>
10#include <memory>
11#include <string_view>
12
13#include <fmt/format.h>
14#include <glass/Context.h>
15#include <glass/MainMenuBar.h>
16#include <glass/Storage.h>
17#include <glass/Window.h>
18#include <glass/WindowManager.h>
19#include <glass/other/Log.h>
20#include <imgui.h>
21#include <uv.h>
22#include <wpi/Logger.h>
23#include <wpigui.h>
24#include <wpigui_openurl.h>
25
26#include "sysid/view/Analyzer.h"
Maxwell Henderson80bec322024-01-09 15:48:44 -080027#include "sysid/view/DataSelector.h"
28#include "sysid/view/LogLoader.h"
James Kuszmaulb13e13f2023-11-22 20:44:04 -080029#include "sysid/view/UILayout.h"
30
31namespace gui = wpi::gui;
32
33static std::unique_ptr<glass::WindowManager> gWindowManager;
34
Maxwell Henderson80bec322024-01-09 15:48:44 -080035glass::Window* gLogLoaderWindow;
36glass::Window* gDataSelectorWindow;
James Kuszmaulb13e13f2023-11-22 20:44:04 -080037glass::Window* gAnalyzerWindow;
38glass::Window* gProgramLogWindow;
39static glass::MainMenuBar gMainMenu;
40
James Kuszmaulb13e13f2023-11-22 20:44:04 -080041glass::LogData gLog;
42wpi::Logger gLogger;
43
44const char* GetWPILibVersion();
45
46namespace sysid {
47std::string_view GetResource_sysid_16_png();
48std::string_view GetResource_sysid_32_png();
49std::string_view GetResource_sysid_48_png();
50std::string_view GetResource_sysid_64_png();
51std::string_view GetResource_sysid_128_png();
52std::string_view GetResource_sysid_256_png();
53std::string_view GetResource_sysid_512_png();
54} // namespace sysid
55
56void Application(std::string_view saveDir) {
57 // Create the wpigui (along with Dear ImGui) and Glass contexts.
58 gui::CreateContext();
59 glass::CreateContext();
60
61 // Add icons
62 gui::AddIcon(sysid::GetResource_sysid_16_png());
63 gui::AddIcon(sysid::GetResource_sysid_32_png());
64 gui::AddIcon(sysid::GetResource_sysid_48_png());
65 gui::AddIcon(sysid::GetResource_sysid_64_png());
66 gui::AddIcon(sysid::GetResource_sysid_128_png());
67 gui::AddIcon(sysid::GetResource_sysid_256_png());
68 gui::AddIcon(sysid::GetResource_sysid_512_png());
69
70 glass::SetStorageName("sysid");
71 glass::SetStorageDir(saveDir.empty() ? gui::GetPlatformSaveFileDir()
72 : saveDir);
73
74 // Add messages from the global sysid logger into the Log window.
75 gLogger.SetLogger([](unsigned int level, const char* file, unsigned int line,
76 const char* msg) {
77 const char* lvl = "";
78 if (level >= wpi::WPI_LOG_CRITICAL) {
79 lvl = "CRITICAL: ";
80 } else if (level >= wpi::WPI_LOG_ERROR) {
81 lvl = "ERROR: ";
82 } else if (level >= wpi::WPI_LOG_WARNING) {
83 lvl = "WARNING: ";
84 } else if (level >= wpi::WPI_LOG_INFO) {
85 lvl = "INFO: ";
86 } else if (level >= wpi::WPI_LOG_DEBUG) {
87 lvl = "DEBUG: ";
88 }
89 std::string filename = std::filesystem::path{file}.filename().string();
90 gLog.Append(fmt::format("{}{} ({}:{})\n", lvl, msg, filename, line));
91#ifndef NDEBUG
92 fmt::print(stderr, "{}{} ({}:{})\n", lvl, msg, filename, line);
93#endif
94 });
95
96 gLogger.set_min_level(wpi::WPI_LOG_DEBUG);
97 // Set the number of workers for the libuv threadpool.
98 uv_os_setenv("UV_THREADPOOL_SIZE", "6");
99
100 // Initialize window manager and add views.
101 auto& storage = glass::GetStorageRoot().GetChild("SysId");
102 gWindowManager = std::make_unique<glass::WindowManager>(storage);
103 gWindowManager->GlobalInit();
104
Maxwell Henderson80bec322024-01-09 15:48:44 -0800105 auto logLoader = std::make_unique<sysid::LogLoader>(storage, gLogger);
106 auto dataSelector = std::make_unique<sysid::DataSelector>(storage, gLogger);
107 auto analyzer = std::make_unique<sysid::Analyzer>(storage, gLogger);
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800108
Maxwell Henderson80bec322024-01-09 15:48:44 -0800109 logLoader->unload.connect([ds = dataSelector.get()] { ds->Reset(); });
110 dataSelector->testdata = [_analyzer = analyzer.get()](auto data) {
111 _analyzer->m_data = data;
112 _analyzer->AnalyzeData();
113 };
114
115 gLogLoaderWindow =
116 gWindowManager->AddWindow("Log Loader", std::move(logLoader));
117
118 gDataSelectorWindow =
119 gWindowManager->AddWindow("Data Selector", std::move(dataSelector));
120
121 gAnalyzerWindow = gWindowManager->AddWindow("Analyzer", std::move(analyzer));
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800122
123 gProgramLogWindow = gWindowManager->AddWindow(
124 "Program Log", std::make_unique<glass::LogView>(&gLog));
125
126 // Set default positions and sizes for windows.
127
128 // Logger window position/size
Maxwell Henderson80bec322024-01-09 15:48:44 -0800129 gLogLoaderWindow->SetDefaultPos(sysid::kLogLoaderWindowPos.x,
130 sysid::kLogLoaderWindowPos.y);
131 gLogLoaderWindow->SetDefaultSize(sysid::kLogLoaderWindowSize.x,
132 sysid::kLogLoaderWindowSize.y);
133
134 // Data selector window position/size
135 gDataSelectorWindow->SetDefaultPos(sysid::kDataSelectorWindowPos.x,
136 sysid::kDataSelectorWindowPos.y);
137 gDataSelectorWindow->SetDefaultSize(sysid::kDataSelectorWindowSize.x,
138 sysid::kDataSelectorWindowSize.y);
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800139
140 // Analyzer window position/size
141 gAnalyzerWindow->SetDefaultPos(sysid::kAnalyzerWindowPos.x,
142 sysid::kAnalyzerWindowPos.y);
143 gAnalyzerWindow->SetDefaultSize(sysid::kAnalyzerWindowSize.x,
144 sysid::kAnalyzerWindowSize.y);
145
146 // Program log window position/size
147 gProgramLogWindow->SetDefaultPos(sysid::kProgramLogWindowPos.x,
148 sysid::kProgramLogWindowPos.y);
149 gProgramLogWindow->SetDefaultSize(sysid::kProgramLogWindowSize.x,
150 sysid::kProgramLogWindowSize.y);
151 gProgramLogWindow->DisableRenamePopup();
152
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800153 // Configure save file.
154 gui::ConfigurePlatformSaveFile("sysid.ini");
155
156 // Add menu bar.
157 gui::AddLateExecute([] {
158 ImGui::BeginMainMenuBar();
159 gMainMenu.WorkspaceMenu();
160 gui::EmitViewMenu();
161
162 if (ImGui::BeginMenu("Widgets")) {
163 gWindowManager->DisplayMenu();
164 ImGui::EndMenu();
165 }
166
167 bool about = false;
168 if (ImGui::BeginMenu("Info")) {
169 if (ImGui::MenuItem("About")) {
170 about = true;
171 }
172 ImGui::EndMenu();
173 }
174
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800175 if (ImGui::BeginMenu("Docs")) {
176 if (ImGui::MenuItem("Online documentation")) {
177 wpi::gui::OpenURL(
178 "https://docs.wpilib.org/en/stable/docs/software/pathplanning/"
179 "system-identification/");
180 }
181
182 ImGui::EndMenu();
183 }
184
185 ImGui::EndMainMenuBar();
186
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800187 if (about) {
188 ImGui::OpenPopup("About");
189 about = false;
190 }
191 if (ImGui::BeginPopupModal("About")) {
192 ImGui::Text("SysId: System Identification for Robot Mechanisms");
193 ImGui::Separator();
194 ImGui::Text("v%s", GetWPILibVersion());
195 ImGui::Separator();
196 ImGui::Text("Save location: %s", glass::GetStorageDir().c_str());
197 if (ImGui::Button("Close")) {
198 ImGui::CloseCurrentPopup();
199 }
200 ImGui::EndPopup();
201 }
202 });
203
204 gui::Initialize("System Identification", sysid::kAppWindowSize.x,
205 sysid::kAppWindowSize.y);
206 gui::Main();
207
208 glass::DestroyContext();
209 gui::DestroyContext();
210}
211
212#endif