2020-12-26 14:31:24 -08:00
|
|
|
// Copyright (c) FIRST and other WPILib contributors.
|
|
|
|
|
// Open Source Software; you can modify and/or share it under the terms of
|
|
|
|
|
// the WPILib BSD license file in the root directory of this project.
|
2020-09-12 10:55:46 -07:00
|
|
|
|
|
|
|
|
#include "glass/other/DeviceTree.h"
|
|
|
|
|
|
|
|
|
|
#include <cinttypes>
|
|
|
|
|
|
|
|
|
|
#include <imgui.h>
|
|
|
|
|
|
|
|
|
|
#include "glass/Context.h"
|
|
|
|
|
#include "glass/ContextInternal.h"
|
|
|
|
|
#include "glass/DataSource.h"
|
|
|
|
|
|
|
|
|
|
using namespace glass;
|
|
|
|
|
|
|
|
|
|
void DeviceTreeModel::Update() {
|
|
|
|
|
for (auto&& display : m_displays) {
|
|
|
|
|
if (display.first) display.first->Update();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DeviceTreeModel::Exists() {
|
|
|
|
|
for (auto&& display : m_displays) {
|
|
|
|
|
if (display.first && display.first->Exists()) return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceTreeModel::Display() {
|
|
|
|
|
for (auto&& display : m_displays) {
|
|
|
|
|
if (display.second) display.second(display.first);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void glass::HideDevice(const char* id) { gContext->deviceHidden[id] = true; }
|
|
|
|
|
|
|
|
|
|
bool glass::BeginDevice(const char* id, ImGuiTreeNodeFlags flags) {
|
|
|
|
|
if (gContext->deviceHidden[id]) return false;
|
|
|
|
|
|
|
|
|
|
PushID(id);
|
|
|
|
|
|
|
|
|
|
// build label
|
|
|
|
|
std::string* name = GetStorage().GetStringRef("name");
|
|
|
|
|
char label[128];
|
|
|
|
|
std::snprintf(label, sizeof(label), "%s###name",
|
|
|
|
|
name->empty() ? id : name->c_str());
|
|
|
|
|
|
|
|
|
|
bool open = CollapsingHeader(label, flags);
|
|
|
|
|
PopupEditName("name", name);
|
|
|
|
|
|
|
|
|
|
if (!open) PopID();
|
|
|
|
|
return open;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void glass::EndDevice() { PopID(); }
|
|
|
|
|
|
|
|
|
|
static bool DeviceBooleanImpl(const char* name, bool readonly, bool* value) {
|
|
|
|
|
if (readonly) {
|
|
|
|
|
ImGui::LabelText(name, "%s", *value ? "true" : "false");
|
|
|
|
|
} else {
|
|
|
|
|
static const char* boolOptions[] = {"false", "true"};
|
|
|
|
|
int val = *value ? 1 : 0;
|
|
|
|
|
if (ImGui::Combo(name, &val, boolOptions, 2)) {
|
|
|
|
|
*value = val;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool DeviceDoubleImpl(const char* name, bool readonly, double* value) {
|
|
|
|
|
if (readonly) {
|
|
|
|
|
ImGui::LabelText(name, "%.6f", *value);
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
return ImGui::InputDouble(name, value, 0, 0, "%.6f",
|
|
|
|
|
ImGuiInputTextFlags_EnterReturnsTrue);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool DeviceEnumImpl(const char* name, bool readonly, int* value,
|
|
|
|
|
const char** options, int32_t numOptions) {
|
|
|
|
|
if (readonly) {
|
|
|
|
|
if (*value < 0 || *value >= numOptions)
|
|
|
|
|
ImGui::LabelText(name, "%d (unknown)", *value);
|
|
|
|
|
else
|
|
|
|
|
ImGui::LabelText(name, "%s", options[*value]);
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
return ImGui::Combo(name, value, options, numOptions);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool DeviceIntImpl(const char* name, bool readonly, int32_t* value) {
|
|
|
|
|
if (readonly) {
|
|
|
|
|
ImGui::LabelText(name, "%" PRId32, *value);
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
return ImGui::InputScalar(name, ImGuiDataType_S32, value, nullptr, nullptr,
|
|
|
|
|
nullptr, ImGuiInputTextFlags_EnterReturnsTrue);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool DeviceLongImpl(const char* name, bool readonly, int64_t* value) {
|
|
|
|
|
if (readonly) {
|
|
|
|
|
ImGui::LabelText(name, "%" PRId64, *value);
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
return ImGui::InputScalar(name, ImGuiDataType_S64, value, nullptr, nullptr,
|
|
|
|
|
nullptr, ImGuiInputTextFlags_EnterReturnsTrue);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename F, typename... Args>
|
|
|
|
|
static inline bool DeviceValueImpl(const char* name, bool readonly,
|
|
|
|
|
const DataSource* source, F&& func,
|
|
|
|
|
Args... args) {
|
|
|
|
|
ImGui::SetNextItemWidth(ImGui::GetWindowWidth() * 0.5f);
|
|
|
|
|
if (!source) {
|
|
|
|
|
return func(name, readonly, args...);
|
|
|
|
|
} else {
|
|
|
|
|
ImGui::PushID(name);
|
|
|
|
|
bool rv = func("", readonly, args...);
|
|
|
|
|
ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
|
|
|
ImGui::Selectable(name);
|
|
|
|
|
source->EmitDrag();
|
|
|
|
|
ImGui::PopID();
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool glass::DeviceBoolean(const char* name, bool readonly, bool* value,
|
|
|
|
|
const DataSource* source) {
|
|
|
|
|
return DeviceValueImpl(name, readonly, source, DeviceBooleanImpl, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool glass::DeviceDouble(const char* name, bool readonly, double* value,
|
|
|
|
|
const DataSource* source) {
|
|
|
|
|
return DeviceValueImpl(name, readonly, source, DeviceDoubleImpl, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool glass::DeviceEnum(const char* name, bool readonly, int* value,
|
|
|
|
|
const char** options, int32_t numOptions,
|
|
|
|
|
const DataSource* source) {
|
|
|
|
|
return DeviceValueImpl(name, readonly, source, DeviceEnumImpl, value, options,
|
|
|
|
|
numOptions);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool glass::DeviceInt(const char* name, bool readonly, int32_t* value,
|
|
|
|
|
const DataSource* source) {
|
|
|
|
|
return DeviceValueImpl(name, readonly, source, DeviceIntImpl, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool glass::DeviceLong(const char* name, bool readonly, int64_t* value,
|
|
|
|
|
const DataSource* source) {
|
|
|
|
|
return DeviceValueImpl(name, readonly, source, DeviceLongImpl, value);
|
|
|
|
|
}
|