Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion glass/src/lib/native/cpp/other/DeviceTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <cinttypes>
#include <string>
#include <string_view>

#include <imgui.h>

Expand Down Expand Up @@ -45,7 +46,16 @@ void wpi::glass::HideDevice(const char* id) {
gContext->deviceHidden[id] = true;
}

bool wpi::glass::IsDeviceHidden(std::string_view id) {
return gContext->deviceHidden[id];
}

bool wpi::glass::BeginDevice(const char* id, ImGuiTreeNodeFlags flags) {
return BeginDevice(std::string_view{id}, std::string_view{id}, flags);
}

bool wpi::glass::BeginDevice(std::string_view id, std::string_view labelText,
ImGuiTreeNodeFlags flags) {
if (gContext->deviceHidden[id]) {
return false;
}
Expand All @@ -56,7 +66,8 @@ bool wpi::glass::BeginDevice(const char* id, ImGuiTreeNodeFlags flags) {
std::string& name = GetStorage().GetString("name");
char label[128];
if (name.empty()) {
wpi::util::format_to_n_c_str(label, sizeof(label), "{}###header", id);
wpi::util::format_to_n_c_str(label, sizeof(label), "{}###header",
labelText);
} else {
wpi::util::format_to_n_c_str(label, sizeof(label), "{}###header", name);
}
Expand Down
23 changes: 23 additions & 0 deletions glass/src/lib/native/include/wpi/glass/other/DeviceTree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#pragma once

#include <memory>
#include <string_view>
#include <utility>
#include <vector>

Expand Down Expand Up @@ -57,6 +58,14 @@ class DeviceTreeModel : public Model {
*/
void HideDevice(const char* id);

/**
* Returns true if a device is hidden on the tree.
*
* @param id device name
* @return True if hidden
*/
bool IsDeviceHidden(std::string_view id);

/**
* Wraps CollapsingHeader() to provide both hiding functionality and open
* persistence. As with the ImGui function, returns true if the tree node
Expand All @@ -69,6 +78,20 @@ void HideDevice(const char* id);
*/
bool BeginDevice(const char* id, ImGuiTreeNodeFlags flags = 0);

/**
* Wraps CollapsingHeader() to provide both hiding functionality and open
* persistence while using a different visible label from the storage ID. As
* with the ImGui function, returns true if the tree node is visible and
* expanded. If returns true, call EndDevice() to finish the block.
*
* @param id storage and hide device name
* @param label visible label
* @param flags ImGuiTreeNodeFlags flags
* @return True if expanded
*/
bool BeginDevice(std::string_view id, std::string_view label,
ImGuiTreeNodeFlags flags = 0);

/**
* Finish a device block started with BeginDevice().
*/
Expand Down
136 changes: 130 additions & 6 deletions simulation/halsim_gui/src/main/native/cpp/SimDeviceGui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,16 @@

#include <stdint.h>

#include <algorithm>
#include <format>
#include <memory>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include "wpi/glass/Context.hpp"
#include "wpi/glass/Storage.hpp"
#include "wpi/glass/other/DeviceTree.hpp"
#include "wpi/hal/SimDevice.hpp"
#include "wpi/hal/simulation/SimDeviceData.h"
Expand Down Expand Up @@ -93,6 +99,21 @@ class SimDevicesModel : public wpi::glass::Model {
std::unique_ptr<wpi::glass::DataSource>>
m_sources;
};

struct SimDeviceTreeDevice {
std::string id;
HAL_SimDeviceHandle handle;
};

struct SimDeviceTreeNode {
SimDeviceTreeNode(std::string_view name, std::string_view id)
: name{name}, id{id} {}

std::string name;
std::string id;
std::vector<SimDeviceTreeDevice> devices;
std::vector<SimDeviceTreeNode> children;
};
} // namespace

static SimDevicesModel* gSimDevicesModel;
Expand Down Expand Up @@ -193,8 +214,7 @@ static void DisplaySimValue(const char* name, void* data,
}
}

static void DisplaySimDevice(const char* name, void* data,
HAL_SimDeviceHandle handle) {
static std::string GetDisplaySimDeviceId(const char* name) {
std::string_view id{name};
if (!gSimDevicesShowPrefix) {
// only show "Foo" portion of "Accel:Foo"
Expand All @@ -204,12 +224,117 @@ static void DisplaySimDevice(const char* name, void* data,
id = type;
}
}
if (wpi::glass::BeginDevice(id.data())) {
HALSIM_EnumerateSimValues(handle, data, DisplaySimValue);

return std::string{id};
}

static SimDeviceTreeNode& GetOrAddChild(SimDeviceTreeNode& node,
std::string_view name) {
auto childIt =
std::find_if(node.children.begin(), node.children.end(),
[&](const auto& child) { return child.name == name; });
if (childIt == node.children.end()) {
std::string id = node.id;
if (!id.empty()) {
id += '/';
}
id += name;
node.children.emplace_back(name, id);
return node.children.back();
}
return *childIt;
}

static void AddSimDevice(SimDeviceTreeNode& root, std::string id,
HAL_SimDeviceHandle handle) {
if (wpi::glass::IsDeviceHidden(id)) {
return;
}

SimDeviceTreeNode* node = &root;
wpi::util::split(id, '/', -1, false, [&](std::string_view segment) {
node = &GetOrAddChild(*node, segment);
});
if (node == &root) {
node = &GetOrAddChild(root, id);
}
node->devices.push_back({std::move(id), handle});
}

static void SortSimDeviceTree(SimDeviceTreeNode& node) {
std::sort(
node.children.begin(), node.children.end(),
[](const auto& lhs, const auto& rhs) { return lhs.name < rhs.name; });

for (auto&& child : node.children) {
SortSimDeviceTree(child);
}
}

static bool BeginSimDeviceTreeNode(const SimDeviceTreeNode& node) {
auto flags = ImGuiTreeNodeFlags_DefaultOpen;
bool& open = wpi::glass::GetStorage()
.GetChild("deviceTree")
.GetChild(node.id)
.GetBool("open", true);
ImGui::SetNextItemOpen(open);

std::string label = std::format("{}###{}", node.name, node.id);
open = ImGui::CollapsingHeader(label.c_str(), flags);
if (open) {
ImGui::Indent();
}
return open;
}

static void EndSimDeviceTreeNode() {
ImGui::Unindent();
}

static void DisplaySimDevice(SimDevicesModel* model,
const SimDeviceTreeDevice& device,
std::string_view label) {
if (wpi::glass::BeginDevice(device.id, label)) {
HALSIM_EnumerateSimValues(device.handle, model, DisplaySimValue);
wpi::glass::EndDevice();
}
}

static void DisplaySimDeviceTree(SimDevicesModel* model,
const SimDeviceTreeNode& node) {
if (node.children.empty()) {
for (auto&& device : node.devices) {
DisplaySimDevice(model, device, node.name);
}
return;
}

if (BeginSimDeviceTreeNode(node)) {
for (auto&& device : node.devices) {
DisplaySimDevice(model, device, node.name);
}
for (auto&& child : node.children) {
DisplaySimDeviceTree(model, child);
}
EndSimDeviceTreeNode();
}
}

static void DisplaySimDevices(SimDevicesModel* model) {
SimDeviceTreeNode root{"", ""};
HALSIM_EnumerateSimDevices(
"", &root, [](const char* name, void* data, HAL_SimDeviceHandle handle) {
AddSimDevice(*static_cast<SimDeviceTreeNode*>(data),
GetDisplaySimDeviceId(name), handle);
});

SortSimDeviceTree(root);

for (auto&& child : root.children) {
DisplaySimDeviceTree(model, child);
}
}

void SimDeviceGui::Initialize() {
HALSimGui::halProvider->Register(
"Other Devices", [] { return true; },
Expand All @@ -231,8 +356,7 @@ void SimDeviceGui::Initialize() {
auto model = std::make_unique<SimDevicesModel>();
gSimDevicesModel = model.get();
GetDeviceTree().Add(std::move(model), [](wpi::glass::Model* model) {
HALSIM_EnumerateSimDevices("", static_cast<SimDevicesModel*>(model),
DisplaySimDevice);
DisplaySimDevices(static_cast<SimDevicesModel*>(model));
});
}

Expand Down
Loading