blob: a20ff8bf547e6d95c86e1df21cff23a03bbb915d [file] [log] [blame]
Austin Schuh812d0d12021-11-04 20:16:48 -07001// 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 <memory>
6
7#include <GLFW/glfw3.h>
8#include <fmt/format.h>
9#include <imgui.h>
10#include <ntcore_cpp.h>
11#include <wpigui.h>
12
13#include "glass/Context.h"
Austin Schuh75263e32022-02-22 18:05:32 -080014#include "glass/MainMenuBar.h"
Austin Schuh812d0d12021-11-04 20:16:48 -070015#include "glass/Model.h"
Austin Schuh75263e32022-02-22 18:05:32 -080016#include "glass/Storage.h"
Austin Schuh812d0d12021-11-04 20:16:48 -070017#include "glass/View.h"
18#include "glass/networktables/NetworkTables.h"
19#include "glass/networktables/NetworkTablesProvider.h"
20#include "glass/networktables/NetworkTablesSettings.h"
21#include "glass/other/Log.h"
22#include "glass/other/Plot.h"
23
24namespace gui = wpi::gui;
25
26const char* GetWPILibVersion();
27
28namespace glass {
29std::string_view GetResource_glass_16_png();
30std::string_view GetResource_glass_32_png();
31std::string_view GetResource_glass_48_png();
32std::string_view GetResource_glass_64_png();
33std::string_view GetResource_glass_128_png();
34std::string_view GetResource_glass_256_png();
35std::string_view GetResource_glass_512_png();
36} // namespace glass
37
38static std::unique_ptr<glass::PlotProvider> gPlotProvider;
39static std::unique_ptr<glass::NetworkTablesProvider> gNtProvider;
40
41static std::unique_ptr<glass::NetworkTablesModel> gNetworkTablesModel;
42static std::unique_ptr<glass::NetworkTablesSettings> gNetworkTablesSettings;
43static glass::LogData gNetworkTablesLog;
Austin Schuh75263e32022-02-22 18:05:32 -080044static std::unique_ptr<glass::Window> gNetworkTablesWindow;
James Kuszmaulcf324122023-01-14 14:07:17 -080045static std::unique_ptr<glass::Window> gNetworkTablesInfoWindow;
Austin Schuh75263e32022-02-22 18:05:32 -080046static std::unique_ptr<glass::Window> gNetworkTablesSettingsWindow;
47static std::unique_ptr<glass::Window> gNetworkTablesLogWindow;
48
49static glass::MainMenuBar gMainMenu;
50static bool gAbout = false;
51static bool gSetEnterKey = false;
52static bool gKeyEdit = false;
James Kuszmaulcf324122023-01-14 14:07:17 -080053static int* gEnterKey;
54static void (*gPrevKeyCallback)(GLFWwindow*, int, int, int, int);
55
56static void RemapEnterKeyCallback(GLFWwindow* window, int key, int scancode,
57 int action, int mods) {
58 if (action == GLFW_PRESS || action == GLFW_RELEASE) {
59 if (gKeyEdit) {
60 *gEnterKey = key;
61 gKeyEdit = false;
62 } else if (*gEnterKey == key) {
63 key = GLFW_KEY_ENTER;
64 }
65 }
66
67 if (gPrevKeyCallback) {
68 gPrevKeyCallback(window, key, scancode, action, mods);
69 }
70}
Austin Schuh812d0d12021-11-04 20:16:48 -070071
72static void NtInitialize() {
Austin Schuh812d0d12021-11-04 20:16:48 -070073 auto inst = nt::GetDefaultInstance();
James Kuszmaulcf324122023-01-14 14:07:17 -080074 auto poller = nt::CreateListenerPoller(inst);
75 nt::AddPolledListener(
76 poller, inst,
77 NT_EVENT_CONNECTION | NT_EVENT_IMMEDIATE | NT_EVENT_LOGMESSAGE);
Austin Schuh812d0d12021-11-04 20:16:48 -070078 gui::AddEarlyExecute([poller] {
79 auto win = gui::GetSystemWindow();
80 if (!win) {
81 return;
82 }
James Kuszmaulcf324122023-01-14 14:07:17 -080083 for (auto&& event : nt::ReadListenerQueue(poller)) {
84 if (auto connInfo = event.GetConnectionInfo()) {
85 // update window title when connection status changes
86 if ((event.flags & NT_EVENT_CONNECTED) != 0) {
87 glfwSetWindowTitle(
88 win, fmt::format("Glass - Connected ({})", connInfo->remote_ip)
89 .c_str());
90 } else {
91 glfwSetWindowTitle(win, "Glass - DISCONNECTED");
92 }
93 } else if (auto msg = event.GetLogMessage()) {
94 const char* level = "";
95 if (msg->level >= NT_LOG_CRITICAL) {
96 level = "CRITICAL: ";
97 } else if (msg->level >= NT_LOG_ERROR) {
98 level = "ERROR: ";
99 } else if (msg->level >= NT_LOG_WARNING) {
100 level = "WARNING: ";
101 }
102 gNetworkTablesLog.Append(fmt::format(
103 "{}{} ({}:{})\n", level, msg->message, msg->filename, msg->line));
Austin Schuh812d0d12021-11-04 20:16:48 -0700104 }
105 }
106 });
107
Austin Schuh75263e32022-02-22 18:05:32 -0800108 gNetworkTablesLogWindow = std::make_unique<glass::Window>(
109 glass::GetStorageRoot().GetChild("NetworkTables Log"),
110 "NetworkTables Log", glass::Window::kHide);
111 gNetworkTablesLogWindow->SetView(
Austin Schuh812d0d12021-11-04 20:16:48 -0700112 std::make_unique<glass::LogView>(&gNetworkTablesLog));
Austin Schuh75263e32022-02-22 18:05:32 -0800113 gNetworkTablesLogWindow->SetDefaultPos(250, 615);
114 gNetworkTablesLogWindow->SetDefaultSize(600, 130);
115 gNetworkTablesLogWindow->DisableRenamePopup();
116 gui::AddLateExecute([] { gNetworkTablesLogWindow->Display(); });
Austin Schuh812d0d12021-11-04 20:16:48 -0700117
118 // NetworkTables table window
119 gNetworkTablesModel = std::make_unique<glass::NetworkTablesModel>();
120 gui::AddEarlyExecute([] { gNetworkTablesModel->Update(); });
121
Austin Schuh75263e32022-02-22 18:05:32 -0800122 gNetworkTablesWindow = std::make_unique<glass::Window>(
123 glass::GetStorageRoot().GetChild("NetworkTables View"), "NetworkTables");
124 gNetworkTablesWindow->SetView(
Austin Schuh812d0d12021-11-04 20:16:48 -0700125 std::make_unique<glass::NetworkTablesView>(gNetworkTablesModel.get()));
Austin Schuh75263e32022-02-22 18:05:32 -0800126 gNetworkTablesWindow->SetDefaultPos(250, 277);
127 gNetworkTablesWindow->SetDefaultSize(750, 185);
128 gNetworkTablesWindow->DisableRenamePopup();
129 gui::AddLateExecute([] { gNetworkTablesWindow->Display(); });
Austin Schuh812d0d12021-11-04 20:16:48 -0700130
James Kuszmaulcf324122023-01-14 14:07:17 -0800131 // NetworkTables info window
132 gNetworkTablesInfoWindow = std::make_unique<glass::Window>(
133 glass::GetStorageRoot().GetChild("NetworkTables Info"),
134 "NetworkTables Info");
135 gNetworkTablesInfoWindow->SetView(glass::MakeFunctionView(
136 [&] { glass::DisplayNetworkTablesInfo(gNetworkTablesModel.get()); }));
137 gNetworkTablesInfoWindow->SetDefaultPos(250, 130);
138 gNetworkTablesInfoWindow->SetDefaultSize(750, 145);
139 gNetworkTablesInfoWindow->SetDefaultVisibility(glass::Window::kHide);
140 gNetworkTablesInfoWindow->DisableRenamePopup();
141 gui::AddLateExecute([] { gNetworkTablesInfoWindow->Display(); });
142
Austin Schuh812d0d12021-11-04 20:16:48 -0700143 // NetworkTables settings window
Austin Schuh75263e32022-02-22 18:05:32 -0800144 gNetworkTablesSettings = std::make_unique<glass::NetworkTablesSettings>(
James Kuszmaulcf324122023-01-14 14:07:17 -0800145 "glass", glass::GetStorageRoot().GetChild("NetworkTables Settings"));
Austin Schuh812d0d12021-11-04 20:16:48 -0700146 gui::AddEarlyExecute([] { gNetworkTablesSettings->Update(); });
147
Austin Schuh75263e32022-02-22 18:05:32 -0800148 gNetworkTablesSettingsWindow = std::make_unique<glass::Window>(
149 glass::GetStorageRoot().GetChild("NetworkTables Settings"),
150 "NetworkTables Settings");
151 gNetworkTablesSettingsWindow->SetView(
152 glass::MakeFunctionView([] { gNetworkTablesSettings->Display(); }));
153 gNetworkTablesSettingsWindow->SetDefaultPos(30, 30);
154 gNetworkTablesSettingsWindow->SetFlags(ImGuiWindowFlags_AlwaysAutoResize);
155 gNetworkTablesSettingsWindow->DisableRenamePopup();
156 gui::AddLateExecute([] { gNetworkTablesSettingsWindow->Display(); });
157
158 gui::AddWindowScaler([](float scale) {
159 // scale default window positions
160 gNetworkTablesLogWindow->ScaleDefault(scale);
161 gNetworkTablesWindow->ScaleDefault(scale);
162 gNetworkTablesSettingsWindow->ScaleDefault(scale);
163 });
Austin Schuh812d0d12021-11-04 20:16:48 -0700164}
165
166#ifdef _WIN32
167int __stdcall WinMain(void* hInstance, void* hPrevInstance, char* pCmdLine,
168 int nCmdShow) {
Austin Schuh75263e32022-02-22 18:05:32 -0800169 int argc = __argc;
170 char** argv = __argv;
Austin Schuh812d0d12021-11-04 20:16:48 -0700171#else
Austin Schuh75263e32022-02-22 18:05:32 -0800172int main(int argc, char** argv) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700173#endif
Austin Schuh75263e32022-02-22 18:05:32 -0800174 std::string_view saveDir;
175 if (argc == 2) {
176 saveDir = argv[1];
177 }
178
Austin Schuh812d0d12021-11-04 20:16:48 -0700179 gui::CreateContext();
180 glass::CreateContext();
181
182 gui::AddIcon(glass::GetResource_glass_16_png());
183 gui::AddIcon(glass::GetResource_glass_32_png());
184 gui::AddIcon(glass::GetResource_glass_48_png());
185 gui::AddIcon(glass::GetResource_glass_64_png());
186 gui::AddIcon(glass::GetResource_glass_128_png());
187 gui::AddIcon(glass::GetResource_glass_256_png());
188 gui::AddIcon(glass::GetResource_glass_512_png());
189
James Kuszmaulcf324122023-01-14 14:07:17 -0800190 gui::AddEarlyExecute(
191 [] { ImGui::DockSpaceOverViewport(ImGui::GetMainViewport()); });
192
193 gui::AddInit([] { ImGui::GetIO().ConfigDockingWithShift = true; });
194
Austin Schuh75263e32022-02-22 18:05:32 -0800195 gPlotProvider = std::make_unique<glass::PlotProvider>(
196 glass::GetStorageRoot().GetChild("Plots"));
197 gNtProvider = std::make_unique<glass::NetworkTablesProvider>(
198 glass::GetStorageRoot().GetChild("NetworkTables"));
Austin Schuh812d0d12021-11-04 20:16:48 -0700199
Austin Schuh75263e32022-02-22 18:05:32 -0800200 glass::SetStorageName("glass");
201 glass::SetStorageDir(saveDir.empty() ? gui::GetPlatformSaveFileDir()
202 : saveDir);
Austin Schuh812d0d12021-11-04 20:16:48 -0700203 gPlotProvider->GlobalInit();
204 gui::AddInit([] { glass::ResetTime(); });
205 gNtProvider->GlobalInit();
Austin Schuh75263e32022-02-22 18:05:32 -0800206 NtInitialize();
Austin Schuh812d0d12021-11-04 20:16:48 -0700207
208 glass::AddStandardNetworkTablesViews(*gNtProvider);
209
Austin Schuh75263e32022-02-22 18:05:32 -0800210 gui::AddLateExecute([] { gMainMenu.Display(); });
211
212 gMainMenu.AddMainMenu([] {
Austin Schuh812d0d12021-11-04 20:16:48 -0700213 if (ImGui::BeginMenu("View")) {
Austin Schuh75263e32022-02-22 18:05:32 -0800214 if (ImGui::MenuItem("Set Enter Key")) {
215 gSetEnterKey = true;
216 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700217 if (ImGui::MenuItem("Reset Time")) {
218 glass::ResetTime();
219 }
220 ImGui::EndMenu();
221 }
222 if (ImGui::BeginMenu("NetworkTables")) {
223 if (gNetworkTablesSettingsWindow) {
224 gNetworkTablesSettingsWindow->DisplayMenuItem("NetworkTables Settings");
225 }
226 if (gNetworkTablesWindow) {
227 gNetworkTablesWindow->DisplayMenuItem("NetworkTables View");
228 }
James Kuszmaulcf324122023-01-14 14:07:17 -0800229 if (gNetworkTablesInfoWindow) {
230 gNetworkTablesInfoWindow->DisplayMenuItem("NetworkTables Info");
231 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700232 if (gNetworkTablesLogWindow) {
233 gNetworkTablesLogWindow->DisplayMenuItem("NetworkTables Log");
234 }
235 ImGui::Separator();
236 gNtProvider->DisplayMenu();
237 ImGui::EndMenu();
238 }
239 if (ImGui::BeginMenu("Plot")) {
240 bool paused = gPlotProvider->IsPaused();
241 if (ImGui::MenuItem("Pause All Plots", nullptr, &paused)) {
242 gPlotProvider->SetPaused(paused);
243 }
244 ImGui::Separator();
245 gPlotProvider->DisplayMenu();
246 ImGui::EndMenu();
247 }
248
Austin Schuh812d0d12021-11-04 20:16:48 -0700249 if (ImGui::BeginMenu("Info")) {
250 if (ImGui::MenuItem("About")) {
Austin Schuh75263e32022-02-22 18:05:32 -0800251 gAbout = true;
Austin Schuh812d0d12021-11-04 20:16:48 -0700252 }
253 ImGui::EndMenu();
254 }
Austin Schuh75263e32022-02-22 18:05:32 -0800255 });
Austin Schuh812d0d12021-11-04 20:16:48 -0700256
Austin Schuh75263e32022-02-22 18:05:32 -0800257 gui::AddLateExecute([] {
258 if (gAbout) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700259 ImGui::OpenPopup("About");
Austin Schuh75263e32022-02-22 18:05:32 -0800260 gAbout = false;
Austin Schuh812d0d12021-11-04 20:16:48 -0700261 }
262 if (ImGui::BeginPopupModal("About")) {
263 ImGui::Text("Glass: A different kind of dashboard");
264 ImGui::Separator();
265 ImGui::Text("v%s", GetWPILibVersion());
Austin Schuh75263e32022-02-22 18:05:32 -0800266 ImGui::Separator();
267 ImGui::Text("Save location: %s", glass::GetStorageDir().c_str());
Austin Schuh812d0d12021-11-04 20:16:48 -0700268 if (ImGui::Button("Close")) {
269 ImGui::CloseCurrentPopup();
270 }
271 ImGui::EndPopup();
272 }
Austin Schuh75263e32022-02-22 18:05:32 -0800273
Austin Schuh75263e32022-02-22 18:05:32 -0800274 if (gSetEnterKey) {
275 ImGui::OpenPopup("Set Enter Key");
276 gSetEnterKey = false;
277 }
278 if (ImGui::BeginPopupModal("Set Enter Key")) {
279 ImGui::Text("Set the key to use to mean 'Enter'");
280 ImGui::Text("This is useful to edit values without the DS disabling");
281 ImGui::Separator();
282
Austin Schuh75263e32022-02-22 18:05:32 -0800283 ImGui::Text("Key:");
284 ImGui::SameLine();
285 char editLabel[40];
286 char nameBuf[32];
James Kuszmaulcf324122023-01-14 14:07:17 -0800287 const char* name = glfwGetKeyName(*gEnterKey, 0);
Austin Schuh75263e32022-02-22 18:05:32 -0800288 if (!name) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800289 std::snprintf(nameBuf, sizeof(nameBuf), "%d", *gEnterKey);
Austin Schuh75263e32022-02-22 18:05:32 -0800290 name = nameBuf;
291 }
292 std::snprintf(editLabel, sizeof(editLabel), "%s###edit",
293 gKeyEdit ? "(press key)" : name);
294 if (ImGui::SmallButton(editLabel)) {
295 gKeyEdit = true;
296 }
297 ImGui::SameLine();
298 if (ImGui::SmallButton("Reset")) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800299 *gEnterKey = GLFW_KEY_ENTER;
Austin Schuh75263e32022-02-22 18:05:32 -0800300 }
301
302 if (ImGui::Button("Close")) {
303 ImGui::CloseCurrentPopup();
304 gKeyEdit = false;
305 }
306 ImGui::EndPopup();
307 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700308 });
309
James Kuszmaulcf324122023-01-14 14:07:17 -0800310 gui::Initialize("Glass - DISCONNECTED", 1024, 768,
311 ImGuiConfigFlags_DockingEnable);
312 gEnterKey = &glass::GetStorageRoot().GetInt("enterKey", GLFW_KEY_ENTER);
313 if (auto win = gui::GetSystemWindow()) {
314 gPrevKeyCallback = glfwSetKeyCallback(win, RemapEnterKeyCallback);
315 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700316 gui::Main();
317
Austin Schuh75263e32022-02-22 18:05:32 -0800318 gNetworkTablesSettingsWindow.reset();
319 gNetworkTablesLogWindow.reset();
320 gNetworkTablesWindow.reset();
Austin Schuh812d0d12021-11-04 20:16:48 -0700321 gNetworkTablesModel.reset();
Austin Schuh812d0d12021-11-04 20:16:48 -0700322 gNtProvider.reset();
323 gPlotProvider.reset();
324
325 glass::DestroyContext();
326 gui::DestroyContext();
Austin Schuh75263e32022-02-22 18:05:32 -0800327
328 return 0;
Austin Schuh812d0d12021-11-04 20:16:48 -0700329}