blob: 3e0adf197dd7cc756304d53ce70921840379fbbc [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"
14#include "glass/Model.h"
15#include "glass/View.h"
16#include "glass/networktables/NetworkTables.h"
17#include "glass/networktables/NetworkTablesProvider.h"
18#include "glass/networktables/NetworkTablesSettings.h"
19#include "glass/other/Log.h"
20#include "glass/other/Plot.h"
21
22namespace gui = wpi::gui;
23
24const char* GetWPILibVersion();
25
26namespace glass {
27std::string_view GetResource_glass_16_png();
28std::string_view GetResource_glass_32_png();
29std::string_view GetResource_glass_48_png();
30std::string_view GetResource_glass_64_png();
31std::string_view GetResource_glass_128_png();
32std::string_view GetResource_glass_256_png();
33std::string_view GetResource_glass_512_png();
34} // namespace glass
35
36static std::unique_ptr<glass::PlotProvider> gPlotProvider;
37static std::unique_ptr<glass::NetworkTablesProvider> gNtProvider;
38
39static std::unique_ptr<glass::NetworkTablesModel> gNetworkTablesModel;
40static std::unique_ptr<glass::NetworkTablesSettings> gNetworkTablesSettings;
41static glass::LogData gNetworkTablesLog;
42static glass::Window* gNetworkTablesWindow;
43static glass::Window* gNetworkTablesSettingsWindow;
44static glass::Window* gNetworkTablesLogWindow;
45
46static void NtInitialize() {
47 // update window title when connection status changes
48 auto inst = nt::GetDefaultInstance();
49 auto poller = nt::CreateConnectionListenerPoller(inst);
50 nt::AddPolledConnectionListener(poller, true);
51 gui::AddEarlyExecute([poller] {
52 auto win = gui::GetSystemWindow();
53 if (!win) {
54 return;
55 }
56 bool timedOut;
57 for (auto&& event : nt::PollConnectionListener(poller, 0, &timedOut)) {
58 if (event.connected) {
59 glfwSetWindowTitle(
60 win, fmt::format("Glass - Connected ({})", event.conn.remote_ip)
61 .c_str());
62 } else {
63 glfwSetWindowTitle(win, "Glass - DISCONNECTED");
64 }
65 }
66 });
67
68 // handle NetworkTables log messages
69 auto logPoller = nt::CreateLoggerPoller(inst);
70 nt::AddPolledLogger(logPoller, NT_LOG_INFO, 100);
71 gui::AddEarlyExecute([logPoller] {
72 bool timedOut;
73 for (auto&& msg : nt::PollLogger(logPoller, 0, &timedOut)) {
74 const char* level = "";
75 if (msg.level >= NT_LOG_CRITICAL) {
76 level = "CRITICAL: ";
77 } else if (msg.level >= NT_LOG_ERROR) {
78 level = "ERROR: ";
79 } else if (msg.level >= NT_LOG_WARNING) {
80 level = "WARNING: ";
81 }
82 gNetworkTablesLog.Append(fmt::format("{}{} ({}:{})\n", level, msg.message,
83 msg.filename, msg.line));
84 }
85 });
86
87 gNetworkTablesLogWindow = gNtProvider->AddWindow(
88 "NetworkTables Log",
89 std::make_unique<glass::LogView>(&gNetworkTablesLog));
90 if (gNetworkTablesLogWindow) {
91 gNetworkTablesLogWindow->SetDefaultPos(250, 615);
92 gNetworkTablesLogWindow->SetDefaultSize(600, 130);
93 gNetworkTablesLogWindow->SetVisible(false);
94 gNetworkTablesLogWindow->DisableRenamePopup();
95 }
96
97 // NetworkTables table window
98 gNetworkTablesModel = std::make_unique<glass::NetworkTablesModel>();
99 gui::AddEarlyExecute([] { gNetworkTablesModel->Update(); });
100
101 gNetworkTablesWindow = gNtProvider->AddWindow(
102 "NetworkTables",
103 std::make_unique<glass::NetworkTablesView>(gNetworkTablesModel.get()));
104 if (gNetworkTablesWindow) {
105 gNetworkTablesWindow->SetDefaultPos(250, 277);
106 gNetworkTablesWindow->SetDefaultSize(750, 185);
107 gNetworkTablesWindow->DisableRenamePopup();
108 }
109
110 // NetworkTables settings window
111 gNetworkTablesSettings = std::make_unique<glass::NetworkTablesSettings>();
112 gui::AddEarlyExecute([] { gNetworkTablesSettings->Update(); });
113
114 gNetworkTablesSettingsWindow = gNtProvider->AddWindow(
115 "NetworkTables Settings", [] { gNetworkTablesSettings->Display(); });
116 if (gNetworkTablesSettingsWindow) {
117 gNetworkTablesSettingsWindow->SetDefaultPos(30, 30);
118 gNetworkTablesSettingsWindow->SetFlags(ImGuiWindowFlags_AlwaysAutoResize);
119 gNetworkTablesSettingsWindow->DisableRenamePopup();
120 }
121}
122
123#ifdef _WIN32
124int __stdcall WinMain(void* hInstance, void* hPrevInstance, char* pCmdLine,
125 int nCmdShow) {
126#else
127int main() {
128#endif
129 gui::CreateContext();
130 glass::CreateContext();
131
132 gui::AddIcon(glass::GetResource_glass_16_png());
133 gui::AddIcon(glass::GetResource_glass_32_png());
134 gui::AddIcon(glass::GetResource_glass_48_png());
135 gui::AddIcon(glass::GetResource_glass_64_png());
136 gui::AddIcon(glass::GetResource_glass_128_png());
137 gui::AddIcon(glass::GetResource_glass_256_png());
138 gui::AddIcon(glass::GetResource_glass_512_png());
139
140 gPlotProvider = std::make_unique<glass::PlotProvider>("Plot");
141 gNtProvider = std::make_unique<glass::NetworkTablesProvider>("NTProvider");
142
143 gui::ConfigurePlatformSaveFile("glass.ini");
144 gPlotProvider->GlobalInit();
145 gui::AddInit([] { glass::ResetTime(); });
146 gNtProvider->GlobalInit();
147 gui::AddInit(NtInitialize);
148
149 glass::AddStandardNetworkTablesViews(*gNtProvider);
150
151 gui::AddLateExecute([] {
152 ImGui::BeginMainMenuBar();
153 gui::EmitViewMenu();
154 if (ImGui::BeginMenu("View")) {
155 if (ImGui::MenuItem("Reset Time")) {
156 glass::ResetTime();
157 }
158 ImGui::EndMenu();
159 }
160 if (ImGui::BeginMenu("NetworkTables")) {
161 if (gNetworkTablesSettingsWindow) {
162 gNetworkTablesSettingsWindow->DisplayMenuItem("NetworkTables Settings");
163 }
164 if (gNetworkTablesWindow) {
165 gNetworkTablesWindow->DisplayMenuItem("NetworkTables View");
166 }
167 if (gNetworkTablesLogWindow) {
168 gNetworkTablesLogWindow->DisplayMenuItem("NetworkTables Log");
169 }
170 ImGui::Separator();
171 gNtProvider->DisplayMenu();
172 ImGui::EndMenu();
173 }
174 if (ImGui::BeginMenu("Plot")) {
175 bool paused = gPlotProvider->IsPaused();
176 if (ImGui::MenuItem("Pause All Plots", nullptr, &paused)) {
177 gPlotProvider->SetPaused(paused);
178 }
179 ImGui::Separator();
180 gPlotProvider->DisplayMenu();
181 ImGui::EndMenu();
182 }
183
184 bool about = false;
185 if (ImGui::BeginMenu("Info")) {
186 if (ImGui::MenuItem("About")) {
187 about = true;
188 }
189 ImGui::EndMenu();
190 }
191 ImGui::EndMainMenuBar();
192
193 if (about) {
194 ImGui::OpenPopup("About");
195 about = false;
196 }
197 if (ImGui::BeginPopupModal("About")) {
198 ImGui::Text("Glass: A different kind of dashboard");
199 ImGui::Separator();
200 ImGui::Text("v%s", GetWPILibVersion());
201 if (ImGui::Button("Close")) {
202 ImGui::CloseCurrentPopup();
203 }
204 ImGui::EndPopup();
205 }
206 });
207
208 gui::Initialize("Glass - DISCONNECTED", 1024, 768);
209 gui::Main();
210
211 gNetworkTablesModel.reset();
212 gNetworkTablesSettings.reset();
213 gNtProvider.reset();
214 gPlotProvider.reset();
215
216 glass::DestroyContext();
217 gui::DestroyContext();
218}