blob: 20f4dcc12e1bbebbb070c1523db4ed72108daeef [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/networktables/NetworkTables.h"
18#include "glass/networktables/NetworkTablesSettings.h"
19#include "glass/other/Log.h"
20
21namespace gui = wpi::gui;
22
23const char* GetWPILibVersion();
24
25namespace ov {
26std::string_view GetResource_ov_16_png();
27std::string_view GetResource_ov_32_png();
28std::string_view GetResource_ov_48_png();
29std::string_view GetResource_ov_64_png();
30std::string_view GetResource_ov_128_png();
31std::string_view GetResource_ov_256_png();
32std::string_view GetResource_ov_512_png();
33} // namespace ov
34
35static std::unique_ptr<glass::NetworkTablesModel> gModel;
36static std::unique_ptr<glass::NetworkTablesSettings> gSettings;
37static glass::LogData gLog;
38static glass::NetworkTablesFlagsSettings gFlagsSettings;
Austin Schuh75263e32022-02-22 18:05:32 -080039static glass::MainMenuBar gMainMenu;
Austin Schuh812d0d12021-11-04 20:16:48 -070040
41static void NtInitialize() {
Austin Schuh812d0d12021-11-04 20:16:48 -070042 auto inst = nt::GetDefaultInstance();
James Kuszmaulcf324122023-01-14 14:07:17 -080043 auto poller = nt::CreateListenerPoller(inst);
44 nt::AddPolledListener(
45 poller, inst,
46 NT_EVENT_CONNECTION | NT_EVENT_IMMEDIATE | NT_EVENT_LOGMESSAGE);
Austin Schuh812d0d12021-11-04 20:16:48 -070047 gui::AddEarlyExecute([inst, poller] {
48 auto win = gui::GetSystemWindow();
49 if (!win) {
50 return;
51 }
James Kuszmaulcf324122023-01-14 14:07:17 -080052 for (auto&& event : nt::ReadListenerQueue(poller)) {
53 if (auto connInfo = event.GetConnectionInfo()) {
54 // update window title when connection status changes
55 if ((nt::GetNetworkMode(inst) & NT_NET_MODE_SERVER) != 0) {
56 // for server mode, just print number of clients connected
57 glfwSetWindowTitle(win,
58 fmt::format("OutlineViewer - {} Clients Connected",
59 nt::GetConnections(inst).size())
60 .c_str());
61 } else if ((event.flags & NT_EVENT_CONNECTED) != 0) {
62 glfwSetWindowTitle(win, fmt::format("OutlineViewer - Connected ({})",
63 connInfo->remote_ip)
64 .c_str());
65 } else {
66 glfwSetWindowTitle(win, "OutlineViewer - DISCONNECTED");
67 }
68 } else if (auto msg = event.GetLogMessage()) {
69 // handle NetworkTables log messages
70 const char* level = "";
71 if (msg->level >= NT_LOG_CRITICAL) {
72 level = "CRITICAL: ";
73 } else if (msg->level >= NT_LOG_ERROR) {
74 level = "ERROR: ";
75 } else if (msg->level >= NT_LOG_WARNING) {
76 level = "WARNING: ";
77 }
78 gLog.Append(fmt::format("{}{} ({}:{})\n", level, msg->message,
79 msg->filename, msg->line));
Austin Schuh812d0d12021-11-04 20:16:48 -070080 }
81 }
82 });
83
Austin Schuh812d0d12021-11-04 20:16:48 -070084 // NetworkTables table window
85 gModel = std::make_unique<glass::NetworkTablesModel>();
86 gui::AddEarlyExecute([] { gModel->Update(); });
87
88 // NetworkTables settings window
Austin Schuh75263e32022-02-22 18:05:32 -080089 gSettings = std::make_unique<glass::NetworkTablesSettings>(
James Kuszmaulcf324122023-01-14 14:07:17 -080090 "outlineviewer",
Austin Schuh75263e32022-02-22 18:05:32 -080091 glass::GetStorageRoot().GetChild("NetworkTables Settings"));
Austin Schuh812d0d12021-11-04 20:16:48 -070092 gui::AddEarlyExecute([] { gSettings->Update(); });
93}
94
95static void DisplayGui() {
96 ImGui::GetStyle().WindowRounding = 0;
97
98 // fill entire OS window with this window
99 ImGui::SetNextWindowPos(ImVec2(0, 0));
100 int width, height;
101 glfwGetWindowSize(gui::GetSystemWindow(), &width, &height);
102 ImGui::SetNextWindowSize(ImVec2(width, height));
103
104 ImGui::Begin("Entries", nullptr,
105 ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_MenuBar |
106 ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
107 ImGuiWindowFlags_NoCollapse);
108
109 gFlagsSettings.Update();
110
111 // can't create popups from within menu, so use flags
112 bool settings = false;
113 bool log = false;
114 bool about = false;
115
116 // main menu
117 ImGui::BeginMenuBar();
Austin Schuh75263e32022-02-22 18:05:32 -0800118 gMainMenu.WorkspaceMenu();
Austin Schuh812d0d12021-11-04 20:16:48 -0700119 gui::EmitViewMenu();
120 if (ImGui::BeginMenu("View")) {
121 gFlagsSettings.DisplayMenu();
122 ImGui::EndMenu();
123 }
124
125 if (ImGui::BeginMenu("Options")) {
126 if (ImGui::MenuItem("Settings")) {
127 settings = true;
128 }
129 ImGui::EndMenu();
130 }
131
132 if (ImGui::BeginMenu("Info")) {
133 if (ImGui::MenuItem("Log")) {
134 log = true;
135 }
136 ImGui::Separator();
137 if (ImGui::MenuItem("About")) {
138 about = true;
139 }
140 ImGui::EndMenu();
141 }
142 ImGui::EndMenuBar();
143
144 // settings popup
145 if (settings) {
146 ImGui::OpenPopup("Settings");
147 }
148 if (ImGui::BeginPopupModal("Settings", nullptr,
149 ImGuiWindowFlags_AlwaysAutoResize)) {
150 if (gSettings->Display()) {
151 ImGui::CloseCurrentPopup();
152 }
153 ImGui::SameLine();
154 if (ImGui::Button("Cancel")) {
155 ImGui::CloseCurrentPopup();
156 }
157 ImGui::EndPopup();
158 }
159
160 // log popup
161 if (log) {
162 ImGui::OpenPopup("Log");
163 }
164 if (ImGui::BeginPopupModal("Log", nullptr,
165 ImGuiWindowFlags_AlwaysAutoResize)) {
166 if (ImGui::Button("Close")) {
167 ImGui::CloseCurrentPopup();
168 }
169 ImGui::BeginChild("Lines", ImVec2(width * 0.75f, height * 0.75f));
170 glass::DisplayLog(&gLog, true);
171 ImGui::EndChild();
172 ImGui::EndPopup();
173 }
174
175 // about popup
176 if (about) {
177 ImGui::OpenPopup("About");
178 }
179 if (ImGui::BeginPopupModal("About", nullptr,
180 ImGuiWindowFlags_AlwaysAutoResize)) {
181 ImGui::Text("OutlineViewer");
182 ImGui::Separator();
183 ImGui::Text("v%s", GetWPILibVersion());
Austin Schuh75263e32022-02-22 18:05:32 -0800184 ImGui::Separator();
185 ImGui::Text("Save location: %s", glass::GetStorageDir().c_str());
Austin Schuh812d0d12021-11-04 20:16:48 -0700186 if (ImGui::Button("Close")) {
187 ImGui::CloseCurrentPopup();
188 }
189 ImGui::EndPopup();
190 }
191
192 // display table view
James Kuszmaulcf324122023-01-14 14:07:17 -0800193 glass::DisplayNetworkTablesInfo(gModel.get());
194 ImGui::Separator();
Austin Schuh812d0d12021-11-04 20:16:48 -0700195 glass::DisplayNetworkTables(gModel.get(), gFlagsSettings.GetFlags());
196
197 ImGui::End();
198}
199
200#ifdef _WIN32
201int __stdcall WinMain(void* hInstance, void* hPrevInstance, char* pCmdLine,
202 int nCmdShow) {
Austin Schuh75263e32022-02-22 18:05:32 -0800203 int argc = __argc;
204 char** argv = __argv;
Austin Schuh812d0d12021-11-04 20:16:48 -0700205#else
Austin Schuh75263e32022-02-22 18:05:32 -0800206int main(int argc, char** argv) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700207#endif
Austin Schuh75263e32022-02-22 18:05:32 -0800208 std::string_view saveDir;
209 if (argc == 2) {
210 saveDir = argv[1];
211 }
212
Austin Schuh812d0d12021-11-04 20:16:48 -0700213 gui::CreateContext();
214 glass::CreateContext();
215
216 gui::AddIcon(ov::GetResource_ov_16_png());
217 gui::AddIcon(ov::GetResource_ov_32_png());
218 gui::AddIcon(ov::GetResource_ov_48_png());
219 gui::AddIcon(ov::GetResource_ov_64_png());
220 gui::AddIcon(ov::GetResource_ov_128_png());
221 gui::AddIcon(ov::GetResource_ov_256_png());
222 gui::AddIcon(ov::GetResource_ov_512_png());
223
Austin Schuh75263e32022-02-22 18:05:32 -0800224 glass::SetStorageName("outlineviewer");
225 glass::SetStorageDir(saveDir.empty() ? gui::GetPlatformSaveFileDir()
226 : saveDir);
227
Austin Schuh812d0d12021-11-04 20:16:48 -0700228 gui::AddInit(NtInitialize);
229
230 gui::AddLateExecute(DisplayGui);
231
232 gui::Initialize("OutlineViewer - DISCONNECTED", 600, 400);
233 gui::Main();
234
235 gModel.reset();
236 gSettings.reset();
237
238 glass::DestroyContext();
239 gui::DestroyContext();
Austin Schuh75263e32022-02-22 18:05:32 -0800240
241 return 0;
Austin Schuh812d0d12021-11-04 20:16:48 -0700242}