[glass] Use JSON files for storage instead of imgui ini

Storage is now nested.

Separate "roots" can be configured which save to separate files.
In particular, this is used to save wpigui and ImGui window position
to a -window.json file.

ImGui's ini (for window position) is mapped to JSON.

You can optionally specify a directory to load from on the command line.
If one isn't provided, it uses the global system directory.
Any changes made are automatically saved here.

Workspace | Open: select directory, the current layout is replaced with that
workspace, and future auto-saves also switch to that location. The main
window size/location is not changed, only the contents.

Workspace | Save As: select directory, the current layout is saved there,
and future auto-saves also switch to that location.

Workspace | Reset: window locations are preserved, but all other settings
are reset to default (including e.g. removing plot windows). This will also
end up clearing the current save file. as with load, the main window
size/location is not changed.

Workspace | Save As Global: "save as" to the global system location

Notably, the main window size/location is only loaded at startup, but is
auto-saved as part of the current workspace.
This commit is contained in:
Peter Johnson
2021-11-25 00:51:00 -08:00
parent 0bbf51d566
commit 0587b7043a
70 changed files with 3007 additions and 2358 deletions

View File

@@ -100,7 +100,7 @@ static bool AddressableLEDsExists() {
}
void AddressableLEDGui::Initialize() {
HALSimGui::halProvider.Register(
HALSimGui::halProvider->Register(
"Addressable LEDs", [] { return AddressableLEDsExists(); },
[] { return std::make_unique<AddressableLEDsModel>(); },
[](glass::Window* win, glass::Model* model) {

View File

@@ -109,7 +109,7 @@ static bool AnalogInputsAnyInitialized() {
}
void AnalogInputSimGui::Initialize() {
HALSimGui::halProvider.Register(
HALSimGui::halProvider->Register(
"Analog Inputs", AnalogInputsAnyInitialized,
[] { return std::make_unique<AnalogInputsSimModel>(); },
[](glass::Window* win, glass::Model* model) {

View File

@@ -232,14 +232,14 @@ static bool DIOAnyInitialized() {
}
void DIOSimGui::Initialize() {
HALSimGui::halProvider.Register(
HALSimGui::halProvider->Register(
"DIO", DIOAnyInitialized, [] { return std::make_unique<DIOsSimModel>(); },
[](glass::Window* win, glass::Model* model) {
win->SetFlags(ImGuiWindowFlags_AlwaysAutoResize);
win->SetDefaultPos(470, 20);
return glass::MakeFunctionView([=] {
glass::DisplayDIOs(static_cast<DIOsSimModel*>(model),
HALSimGui::halProvider.AreOutputsEnabled());
HALSimGui::halProvider->AreOutputsEnabled());
});
});
}

View File

@@ -6,13 +6,14 @@
#include <glass/WindowManager.h>
#include <memory>
#include <string_view>
namespace halsimgui {
class DSManager : public glass::WindowManager {
public:
explicit DSManager(std::string_view iniName) : WindowManager{iniName} {}
explicit DSManager(glass::Storage& storage) : WindowManager{storage} {}
void DisplayMenu() override;
};
@@ -22,7 +23,7 @@ class DriverStationGui {
static void GlobalInit();
static void SetDSSocketExtension(void* data);
static DSManager dsManager;
static std::unique_ptr<DSManager> dsManager;
};
} // namespace halsimgui

View File

@@ -246,7 +246,7 @@ static bool EncodersAnyInitialized() {
}
void EncoderSimGui::Initialize() {
HALSimGui::halProvider.Register(
HALSimGui::halProvider->Register(
"Encoders", EncodersAnyInitialized,
[] { return std::make_unique<EncodersSimModel>(); },
[](glass::Window* win, glass::Model* model) {
@@ -258,7 +258,7 @@ void EncoderSimGui::Initialize() {
}
glass::EncodersModel& EncoderSimGui::GetEncodersModel() {
static auto model = HALSimGui::halProvider.GetModel("Encoders");
static auto model = HALSimGui::halProvider->GetModel("Encoders");
assert(model);
return *static_cast<glass::EncodersModel*>(model);
}

View File

@@ -5,6 +5,7 @@
#include "HALProvider.h"
#include <glass/Model.h>
#include <glass/Storage.h>
#include <algorithm>
#include <string>
@@ -15,6 +16,32 @@ using namespace halsimgui;
static bool gDisableOutputsOnDSDisable = true;
HALProvider::HALProvider(glass::Storage& storage) : Provider{storage} {
storage.SetCustomApply([this] {
for (auto&& childIt : m_storage.GetChildren()) {
auto it = FindViewEntry(childIt.key());
if (it != m_viewEntries.end() && (*it)->name == childIt.key()) {
Show(it->get(), nullptr);
}
}
for (auto&& entry : m_viewEntries) {
if (entry->showDefault) {
Show(entry.get(), entry->window);
if (entry->window) {
entry->window->SetDefaultVisibility(glass::Window::kShow);
}
}
}
});
storage.SetCustomClear([this, &storage] {
for (auto&& entry : m_viewEntries) {
entry->window = nullptr;
}
m_windows.clear();
storage.ClearValues();
});
}
bool HALProvider::AreOutputsDisabled() {
return gDisableOutputsOnDSDisable && !HALSIM_GetDriverStationEnabled();
}
@@ -28,34 +55,17 @@ void HALProvider::DisplayMenu() {
bool visible = viewEntry->window && viewEntry->window->IsVisible();
bool wasVisible = visible;
bool exists = viewEntry->modelEntry->exists();
ImGui::MenuItem(viewEntry->name.c_str(), nullptr, &visible,
visible || exists);
if (!wasVisible && visible) {
Show(viewEntry.get(), viewEntry->window);
} else if (wasVisible && !visible && viewEntry->window) {
viewEntry->window->SetVisible(false);
if (ImGui::MenuItem(viewEntry->name.c_str(), nullptr, &visible,
visible || exists)) {
if (!wasVisible && visible) {
Show(viewEntry.get(), viewEntry->window);
} else if (wasVisible && !visible && viewEntry->window) {
viewEntry->window->SetVisible(false);
}
}
}
}
void HALProvider::Update() {
Provider::Update();
// check for visible windows that need displays (typically this is due to
// file loading)
for (auto&& window : m_windows) {
if (!window->IsVisible() || window->HasView()) {
continue;
}
auto id = window->GetId();
auto it = FindViewEntry(id);
if (it == m_viewEntries.end() || (*it)->name != id) {
continue;
}
Show(it->get(), window.get());
}
}
glass::Model* HALProvider::GetModel(std::string_view name) {
auto it = FindModelEntry(name);
if (it == m_modelEntries.end() || (*it)->name != name) {
@@ -87,7 +97,7 @@ void HALProvider::Show(ViewEntry* entry, glass::Window* window) {
// the window might exist and we're just not associated to it yet
if (!window) {
window = GetOrAddWindow(entry->name, true);
window = GetOrAddWindow(entry->name, true, glass::Window::kHide);
}
if (!window) {
return;

View File

@@ -4,22 +4,31 @@
#include "HALSimGui.h"
#include <glass/Context.h>
#include <glass/Storage.h>
#include <imgui.h>
#include <wpigui.h>
using namespace halsimgui;
glass::MainMenuBar HALSimGui::mainMenu;
glass::WindowManager HALSimGui::manager{"SimWindow"};
HALProvider HALSimGui::halProvider{"HALProvider"};
glass::NetworkTablesProvider HALSimGui::ntProvider{"NTProvider"};
std::unique_ptr<glass::WindowManager> HALSimGui::manager;
std::unique_ptr<HALProvider> HALSimGui::halProvider;
std::unique_ptr<glass::NetworkTablesProvider> HALSimGui::ntProvider;
void HALSimGui::GlobalInit() {
manager.GlobalInit();
halProvider.GlobalInit();
ntProvider.GlobalInit();
manager = std::make_unique<glass::WindowManager>(
glass::GetStorageRoot().GetChild("SimWindow"));
manager->GlobalInit();
halProvider = std::make_unique<HALProvider>(
glass::GetStorageRoot().GetChild("HALProvider"));
halProvider->GlobalInit();
ntProvider = std::make_unique<glass::NetworkTablesProvider>(
glass::GetStorageRoot().GetChild("NTProvider"));
ntProvider->GlobalInit();
wpi::gui::AddLateExecute([] { mainMenu.Display(); });
glass::AddStandardNetworkTablesViews(ntProvider);
glass::AddStandardNetworkTablesViews(*ntProvider);
}

View File

@@ -4,6 +4,8 @@
#include "NetworkTablesSimGui.h"
#include <glass/Context.h>
#include <glass/Storage.h>
#include <glass/networktables/NetworkTables.h>
#include <wpigui.h>
@@ -13,21 +15,24 @@
using namespace halsimgui;
static std::unique_ptr<glass::NetworkTablesModel> gNetworkTablesModel;
static std::unique_ptr<glass::NetworkTablesView> gNetworkTablesView;
static glass::Window* gNetworkTablesWindow;
static std::unique_ptr<glass::Window> gNetworkTablesWindow;
void NetworkTablesSimGui::Initialize() {
gNetworkTablesModel = std::make_unique<glass::NetworkTablesModel>();
gNetworkTablesView =
std::make_unique<glass::NetworkTablesView>(gNetworkTablesModel.get());
wpi::gui::AddEarlyExecute([] { gNetworkTablesModel->Update(); });
gNetworkTablesWindow = HALSimGui::ntProvider.AddWindow(
"NetworkTables", [] { gNetworkTablesView->Display(); });
if (gNetworkTablesWindow) {
gNetworkTablesWindow->SetDefaultPos(250, 277);
gNetworkTablesWindow->SetDefaultSize(750, 185);
gNetworkTablesWindow->DisableRenamePopup();
}
gNetworkTablesWindow = std::make_unique<glass::Window>(
glass::GetStorageRoot().GetChild("NetworkTables View"), "NetworkTables");
gNetworkTablesWindow->SetView(
std::make_unique<glass::NetworkTablesView>(gNetworkTablesModel.get()));
gNetworkTablesWindow->SetDefaultPos(250, 277);
gNetworkTablesWindow->SetDefaultSize(750, 185);
gNetworkTablesWindow->DisableRenamePopup();
wpi::gui::AddLateExecute([] { gNetworkTablesWindow->Display(); });
wpi::gui::AddWindowScaler([](float scale) {
// scale default window positions
gNetworkTablesWindow->ScaleDefault(scale);
});
}
void NetworkTablesSimGui::DisplayMenu() {

View File

@@ -197,10 +197,10 @@ static bool PCMsAnyInitialized() {
}
void PCMSimGui::Initialize() {
HALSimGui::halProvider.RegisterModel("CTREPCMs", PCMsAnyInitialized, [] {
HALSimGui::halProvider->RegisterModel("CTREPCMs", PCMsAnyInitialized, [] {
return std::make_unique<PCMsSimModel>();
});
HALSimGui::halProvider.RegisterView(
HALSimGui::halProvider->RegisterView(
"Solenoids", "CTREPCMs",
[](glass::Model* model) {
bool any = false;
@@ -218,14 +218,14 @@ void PCMSimGui::Initialize() {
return glass::MakeFunctionView([=] {
glass::DisplayPCMsSolenoids(
static_cast<PCMsSimModel*>(model),
HALSimGui::halProvider.AreOutputsEnabled());
HALSimGui::halProvider->AreOutputsEnabled());
});
});
SimDeviceGui::GetDeviceTree().Add(
HALSimGui::halProvider.GetModel("CTREPCMs"), [](glass::Model* model) {
HALSimGui::halProvider->GetModel("CTREPCMs"), [](glass::Model* model) {
glass::DisplayCompressorsDevice(
static_cast<PCMsSimModel*>(model),
HALSimGui::halProvider.AreOutputsEnabled());
HALSimGui::halProvider->AreOutputsEnabled());
});
}

View File

@@ -105,7 +105,7 @@ static bool PWMsAnyInitialized() {
}
void PWMSimGui::Initialize() {
HALSimGui::halProvider.Register(
HALSimGui::halProvider->Register(
"PWM Outputs", PWMsAnyInitialized,
[] { return std::make_unique<PWMsSimModel>(); },
[](glass::Window* win, glass::Model* model) {
@@ -113,7 +113,7 @@ void PWMSimGui::Initialize() {
win->SetDefaultPos(910, 20);
return glass::MakeFunctionView([=] {
glass::DisplayPWMs(static_cast<PWMsSimModel*>(model),
HALSimGui::halProvider.AreOutputsEnabled());
HALSimGui::halProvider->AreOutputsEnabled());
});
});
}

View File

@@ -124,7 +124,7 @@ static bool PowerDistributionsAnyInitialized() {
}
void PowerDistributionSimGui::Initialize() {
HALSimGui::halProvider.Register(
HALSimGui::halProvider->Register(
"PowerDistributions", PowerDistributionsAnyInitialized,
[] { return std::make_unique<PowerDistributionsSimModel>(); },
[](glass::Window* win, glass::Model* model) {

View File

@@ -104,7 +104,7 @@ static bool RelayAnyInitialized() {
}
void RelaySimGui::Initialize() {
HALSimGui::halProvider.Register(
HALSimGui::halProvider->Register(
"Relays", RelayAnyInitialized,
[] { return std::make_unique<RelaysSimModel>(); },
[](glass::Window* win, glass::Model* model) {
@@ -112,7 +112,7 @@ void RelaySimGui::Initialize() {
win->SetDefaultPos(180, 20);
return glass::MakeFunctionView([=] {
glass::DisplayRelays(static_cast<RelaysSimModel*>(model),
HALSimGui::halProvider.AreOutputsEnabled());
HALSimGui::halProvider->AreOutputsEnabled());
});
});
}

View File

@@ -132,7 +132,7 @@ class RoboRioSimModel : public glass::RoboRioModel {
} // namespace
void RoboRioSimGui::Initialize() {
HALSimGui::halProvider.Register(
HALSimGui::halProvider->Register(
"RoboRIO", [] { return true; },
[] { return std::make_unique<RoboRioSimModel>(); },
[](glass::Window* win, glass::Model* model) {

View File

@@ -155,7 +155,7 @@ static void DisplaySimDevice(const char* name, void* data,
}
void SimDeviceGui::Initialize() {
HALSimGui::halProvider.Register(
HALSimGui::halProvider->Register(
"Other Devices", [] { return true; },
[] { return std::make_unique<glass::DeviceTreeModel>(); },
[](glass::Window* win, glass::Model* model) {
@@ -170,7 +170,7 @@ void SimDeviceGui::Initialize() {
static_cast<glass::DeviceTreeModel*>(model)->Display();
});
});
HALSimGui::halProvider.ShowDefault("Other Devices");
HALSimGui::halProvider->ShowDefault("Other Devices");
auto model = std::make_unique<SimDevicesModel>();
gSimDevicesModel = model.get();
@@ -185,7 +185,7 @@ glass::DataSource* SimDeviceGui::GetValueSource(HAL_SimValueHandle handle) {
}
glass::DeviceTreeModel& SimDeviceGui::GetDeviceTree() {
static auto model = HALSimGui::halProvider.GetModel("Other Devices");
static auto model = HALSimGui::halProvider->GetModel("Other Devices");
assert(model);
return *static_cast<glass::DeviceTreeModel*>(model);
}

View File

@@ -71,7 +71,7 @@ static void DisplayTiming() {
}
void TimingGui::Initialize() {
HALSimGui::halProvider.Register(
HALSimGui::halProvider->Register(
"Timing", [] { return true; },
[] { return std::make_unique<TimingModel>(); },
[](glass::Window* win, glass::Model* model) {
@@ -80,5 +80,5 @@ void TimingGui::Initialize() {
win->SetDefaultPos(5, 150);
return glass::MakeFunctionView(DisplayTiming);
});
HALSimGui::halProvider.ShowDefault("Timing");
HALSimGui::halProvider->ShowDefault("Timing");
}

View File

@@ -3,6 +3,7 @@
// the WPILib BSD license file in the root directory of this project.
#include <glass/Context.h>
#include <glass/Storage.h>
#include <glass/other/Plot.h>
#include <cstdio>
@@ -35,7 +36,7 @@ using namespace halsimgui;
namespace gui = wpi::gui;
static glass::PlotProvider gPlotProvider{"Plot"};
static std::unique_ptr<glass::PlotProvider> gPlotProvider;
extern "C" {
#if defined(WIN32) || defined(_WIN32)
@@ -46,54 +47,59 @@ __declspec(dllexport)
gui::CreateContext();
glass::CreateContext();
glass::SetStorageName("simgui");
HALSimGui::GlobalInit();
DriverStationGui::GlobalInit();
gPlotProvider.GlobalInit();
gPlotProvider = std::make_unique<glass::PlotProvider>(
glass::GetStorageRoot().GetChild("Plot"));
gPlotProvider->GlobalInit();
// These need to initialize first
gui::AddInit(EncoderSimGui::Initialize);
gui::AddInit(SimDeviceGui::Initialize);
EncoderSimGui::Initialize();
SimDeviceGui::Initialize();
gui::AddInit(AccelerometerSimGui::Initialize);
gui::AddInit(AddressableLEDGui::Initialize);
gui::AddInit(AnalogGyroSimGui::Initialize);
gui::AddInit(AnalogInputSimGui::Initialize);
gui::AddInit(AnalogOutputSimGui::Initialize);
gui::AddInit(DIOSimGui::Initialize);
gui::AddInit(NetworkTablesSimGui::Initialize);
gui::AddInit(PCMSimGui::Initialize);
gui::AddInit(PowerDistributionSimGui::Initialize);
gui::AddInit(PWMSimGui::Initialize);
gui::AddInit(RelaySimGui::Initialize);
gui::AddInit(RoboRioSimGui::Initialize);
gui::AddInit(TimingGui::Initialize);
AccelerometerSimGui::Initialize();
AddressableLEDGui::Initialize();
AnalogGyroSimGui::Initialize();
AnalogInputSimGui::Initialize();
AnalogOutputSimGui::Initialize();
DIOSimGui::Initialize();
NetworkTablesSimGui::Initialize();
PCMSimGui::Initialize();
PowerDistributionSimGui::Initialize();
PWMSimGui::Initialize();
RelaySimGui::Initialize();
RoboRioSimGui::Initialize();
TimingGui::Initialize();
HALSimGui::mainMenu.AddMainMenu([] {
if (ImGui::BeginMenu("Hardware")) {
HALSimGui::halProvider.DisplayMenu();
HALSimGui::halProvider->DisplayMenu();
ImGui::EndMenu();
}
if (ImGui::BeginMenu("NetworkTables")) {
NetworkTablesSimGui::DisplayMenu();
ImGui::Separator();
HALSimGui::ntProvider.DisplayMenu();
HALSimGui::ntProvider->DisplayMenu();
ImGui::EndMenu();
}
if (ImGui::BeginMenu("DS")) {
DriverStationGui::dsManager.DisplayMenu();
DriverStationGui::dsManager->DisplayMenu();
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Plot")) {
bool paused = gPlotProvider.IsPaused();
bool paused = gPlotProvider->IsPaused();
if (ImGui::MenuItem("Pause All Plots", nullptr, &paused)) {
gPlotProvider.SetPaused(paused);
gPlotProvider->SetPaused(paused);
}
ImGui::Separator();
gPlotProvider.DisplayMenu();
gPlotProvider->DisplayMenu();
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Window")) {
HALSimGui::manager.DisplayMenu();
HALSimGui::manager->DisplayMenu();
ImGui::EndMenu();
}
});