diff --git a/glass/src/lib/native/cpp/support/EnumSetting.cpp b/glass/src/lib/native/cpp/support/EnumSetting.cpp index 167cf1b7d25..d5a0017b574 100644 --- a/glass/src/lib/native/cpp/support/EnumSetting.cpp +++ b/glass/src/lib/native/cpp/support/EnumSetting.cpp @@ -41,6 +41,27 @@ bool EnumSetting::Combo(const char* label, int numOptions, return false; } +bool EnumSetting::Menu(const char* label) { + if (m_value == -1) { + UpdateValue(); + } + + int i = 0; + bool change = false; + if (ImGui::BeginMenu(label)) { + for (auto choice : m_choices) { + if (ImGui::MenuItem(choice, nullptr, i == m_value)) { + SetValue(i); + change = true; + } + ++i; + } + ImGui::EndMenu(); + } + + return change; +} + void EnumSetting::UpdateValue() const { // override default value if str is one of the choices int i = 0; diff --git a/glass/src/lib/native/include/glass/support/EnumSetting.h b/glass/src/lib/native/include/glass/support/EnumSetting.h index eaf308fdb4d..ce8964e49c1 100644 --- a/glass/src/lib/native/include/glass/support/EnumSetting.h +++ b/glass/src/lib/native/include/glass/support/EnumSetting.h @@ -22,6 +22,8 @@ class EnumSetting { bool Combo(const char* label, int numOptions = -1, int popup_max_height_in_items = -1); + bool Menu(const char* label); + private: void UpdateValue() const; diff --git a/glass/src/libnt/native/cpp/NetworkTables.cpp b/glass/src/libnt/native/cpp/NetworkTables.cpp index d661ee5f05f..206edae83bb 100644 --- a/glass/src/libnt/native/cpp/NetworkTables.cpp +++ b/glass/src/libnt/native/cpp/NetworkTables.cpp @@ -1667,38 +1667,78 @@ static void EmitValueName(DataSource* source, const char* name, static void EmitValueTree( const std::vector& children, + NetworkTablesFlags flags); + +static void EmitValueTreeChild( + const NetworkTablesModel::EntryValueTreeNode& child, NetworkTablesFlags flags) { - for (auto&& child : children) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - EmitValueName(child.source.get(), child.name.c_str(), child.path.c_str()); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + EmitValueName(child.source.get(), child.name.c_str(), child.path.c_str()); - ImGui::TableNextColumn(); - if (!child.valueChildren.empty()) { - auto pos = ImGui::GetCursorPos(); - char label[128]; - std::string_view ts = child.typeStr; - bool havePopup = GetHeadingTypeString(&ts); - wpi::format_to_n_c_str(label, sizeof(label), "{}##v_{}", ts.data(), - child.name.c_str()); - bool valueChildrenOpen = - TreeNodeEx(label, ImGuiTreeNodeFlags_SpanFullWidth); - if (havePopup) { - if (ImGui::IsItemHovered()) { - ImGui::BeginTooltip(); - ImGui::TextUnformatted(child.typeStr.c_str()); - ImGui::EndTooltip(); - } + ImGui::TableNextColumn(); + if (!child.valueChildren.empty()) { + auto pos = ImGui::GetCursorPos(); + char label[128]; + std::string_view ts = child.typeStr; + bool havePopup = GetHeadingTypeString(&ts); + wpi::format_to_n_c_str(label, sizeof(label), "{}##v_{}", ts.data(), + child.name.c_str()); + bool valueChildrenOpen = + TreeNodeEx(label, ImGuiTreeNodeFlags_SpanFullWidth); + if (havePopup) { + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::TextUnformatted(child.typeStr.c_str()); + ImGui::EndTooltip(); } - // make it look like a normal label w/type - ImGui::SetCursorPos(pos); - ImGui::LabelText(child.valueChildrenMap ? "{...}" : "[...]", "%s", ""); - if (valueChildrenOpen) { - EmitValueTree(child.valueChildren, flags); - TreePop(); + } + // make it look like a normal label w/type + ImGui::SetCursorPos(pos); + ImGui::LabelText(child.valueChildrenMap ? "{...}" : "[...]", "%s", ""); + if (valueChildrenOpen) { + EmitValueTree(child.valueChildren, flags); + TreePop(); + } + } else { + EmitEntryValueReadonly(child, nullptr, flags); + } +} + +static void EmitValueTree( + const std::vector& children, + NetworkTablesFlags flags) { + NetworkTablesOrdering order = (flags & NetworkTablesFlags_Ordering) >> + kNetworkTablesFlags_OrderingBitShift; + + if (order == NetworkTablesOrdering_Combined) { + // All in order + for (auto&& child : children) { + EmitValueTreeChild(child, flags); + } + } else if (order == NetworkTablesOrdering_EntriesFirst) { + // All entries, then all subtables + for (auto&& child : children) { + if (child.valueChildren.empty()) { + EmitValueTreeChild(child, flags); + } + } + for (auto&& child : children) { + if (!child.valueChildren.empty()) { + EmitValueTreeChild(child, flags); + } + } + } else if (order == NetworkTablesOrdering_SubtablesFirst) { + // All subtables, then all entries + for (auto&& child : children) { + if (!child.valueChildren.empty()) { + EmitValueTreeChild(child, flags); + } + } + for (auto&& child : children) { + if (child.valueChildren.empty()) { + EmitValueTreeChild(child, flags); } - } else { - EmitEntryValueReadonly(child, nullptr, flags); } } } @@ -1829,28 +1869,69 @@ static void EmitEntry(NetworkTablesModel* model, } } +static void EmitTree(NetworkTablesModel* model, + const std::vector& tree, + NetworkTablesFlags flags, ShowCategory category, + bool root); + +static void EmitTreeNode(NetworkTablesModel* model, + const NetworkTablesModel::TreeNode& node, + NetworkTablesFlags flags, ShowCategory category, + bool root) { + if (root && (flags & NetworkTablesFlags_ShowSpecial) == 0 && + wpi::starts_with(node.name, '$')) { + return; + } + if (node.entry) { + EmitEntry(model, *node.entry, node.name.c_str(), flags, category); + } + + if (!node.children.empty()) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + bool open = TreeNodeEx(node.name.c_str(), ImGuiTreeNodeFlags_SpanFullWidth); + EmitParentContextMenu(model, node.path, flags); + if (open) { + EmitTree(model, node.children, flags, category, false); + TreePop(); + } + } +} + static void EmitTree(NetworkTablesModel* model, const std::vector& tree, NetworkTablesFlags flags, ShowCategory category, bool root) { - for (auto&& node : tree) { - if (root && (flags & NetworkTablesFlags_ShowSpecial) == 0 && - wpi::starts_with(node.name, '$')) { - continue; + NetworkTablesOrdering order = (flags & NetworkTablesFlags_Ordering) >> + kNetworkTablesFlags_OrderingBitShift; + + if (order == NetworkTablesOrdering_Combined) { + // All in order + for (auto&& node : tree) { + EmitTreeNode(model, node, flags, category, root); + } + } else if (order == NetworkTablesOrdering_EntriesFirst) { + // All entries, then all subtables + for (auto&& node : tree) { + if (node.entry) { + EmitTreeNode(model, node, flags, category, root); + } } - if (node.entry) { - EmitEntry(model, *node.entry, node.name.c_str(), flags, category); + for (auto&& node : tree) { + if (!node.entry) { + EmitTreeNode(model, node, flags, category, root); + } } - - if (!node.children.empty()) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - bool open = - TreeNodeEx(node.name.c_str(), ImGuiTreeNodeFlags_SpanFullWidth); - EmitParentContextMenu(model, node.path, flags); - if (open) { - EmitTree(model, node.children, flags, category, false); - TreePop(); + } else if (order == NetworkTablesOrdering_SubtablesFirst) { + // All subtables, then all entries + for (auto&& node : tree) { + if (!node.entry) { + EmitTreeNode(model, node, flags, category, root); + } + } + for (auto&& node : tree) { + if (node.entry) { + EmitTreeNode(model, node, flags, category, root); } } } @@ -2073,17 +2154,24 @@ void NetworkTablesFlagsSettings::Update() { m_pCreateNoncanonicalKeys = &storage.GetBool( "createNonCanonical", m_defaultFlags & NetworkTablesFlags_CreateNoncanonicalKeys); + m_pOrdering = std::make_unique( + storage.GetString("ordering"), + (m_defaultFlags & NetworkTablesFlags_Ordering) >> + kNetworkTablesFlags_OrderingBitShift, + std::initializer_list( + {"Combined", "Entries First", "Subtables First"})); m_pPrecision = &storage.GetInt( "precision", (m_defaultFlags & NetworkTablesFlags_Precision) >> kNetworkTablesFlags_PrecisionBitShift); } - m_flags &= ~( - NetworkTablesFlags_TreeView | NetworkTablesFlags_CombinedView | - NetworkTablesFlags_ShowSpecial | NetworkTablesFlags_ShowProperties | - NetworkTablesFlags_ShowTimestamp | - NetworkTablesFlags_ShowServerTimestamp | - NetworkTablesFlags_CreateNoncanonicalKeys | NetworkTablesFlags_Precision); + m_flags &= + ~(NetworkTablesFlags_TreeView | NetworkTablesFlags_CombinedView | + NetworkTablesFlags_ShowSpecial | NetworkTablesFlags_ShowProperties | + NetworkTablesFlags_ShowTimestamp | + NetworkTablesFlags_ShowServerTimestamp | + NetworkTablesFlags_CreateNoncanonicalKeys | + NetworkTablesFlags_Ordering | NetworkTablesFlags_Precision); m_flags |= (*m_pTreeView ? NetworkTablesFlags_TreeView : 0) | (*m_pCombinedView ? NetworkTablesFlags_CombinedView : 0) | @@ -2093,6 +2181,7 @@ void NetworkTablesFlagsSettings::Update() { (*m_pShowServerTimestamp ? NetworkTablesFlags_ShowServerTimestamp : 0) | (*m_pCreateNoncanonicalKeys ? NetworkTablesFlags_CreateNoncanonicalKeys : 0) | + (m_pOrdering->GetValue() << kNetworkTablesFlags_OrderingBitShift) | (*m_pPrecision << kNetworkTablesFlags_PrecisionBitShift); } @@ -2106,6 +2195,7 @@ void NetworkTablesFlagsSettings::DisplayMenu() { ImGui::MenuItem("Show Properties", "", m_pShowProperties); ImGui::MenuItem("Show Timestamp", "", m_pShowTimestamp); ImGui::MenuItem("Show Server Timestamp", "", m_pShowServerTimestamp); + m_pOrdering->Menu("Entry Ordering"); if (ImGui::BeginMenu("Decimal Precision")) { static const char* precisionOptions[] = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}; diff --git a/glass/src/libnt/native/include/glass/networktables/NetworkTables.h b/glass/src/libnt/native/include/glass/networktables/NetworkTables.h index bca5a411925..aed30c46d30 100644 --- a/glass/src/libnt/native/include/glass/networktables/NetworkTables.h +++ b/glass/src/libnt/native/include/glass/networktables/NetworkTables.h @@ -26,6 +26,7 @@ #include "glass/Model.h" #include "glass/View.h" +#include "glass/support/EnumSetting.h" namespace glass { @@ -201,9 +202,18 @@ class NetworkTablesModel : public Model { #endif }; +using NetworkTablesOrdering = int; + +enum NetworkTablesOrdering_ { + NetworkTablesOrdering_Combined = 0, + NetworkTablesOrdering_EntriesFirst, + NetworkTablesOrdering_SubtablesFirst, +}; + using NetworkTablesFlags = int; -static constexpr const int kNetworkTablesFlags_PrecisionBitShift = 9; +static constexpr const int kNetworkTablesFlags_OrderingBitShift = 9; +static constexpr const int kNetworkTablesFlags_PrecisionBitShift = 11; enum NetworkTablesFlags_ { NetworkTablesFlags_TreeView = 1 << 0, @@ -214,6 +224,7 @@ enum NetworkTablesFlags_ { NetworkTablesFlags_ShowTimestamp = 1 << 5, NetworkTablesFlags_ShowServerTimestamp = 1 << 6, NetworkTablesFlags_CreateNoncanonicalKeys = 1 << 7, + NetworkTablesFlags_Ordering = 0b11 << kNetworkTablesFlags_OrderingBitShift, NetworkTablesFlags_Precision = 0xff << kNetworkTablesFlags_PrecisionBitShift, NetworkTablesFlags_Default = NetworkTablesFlags_TreeView | (6 << kNetworkTablesFlags_PrecisionBitShift), @@ -248,6 +259,7 @@ class NetworkTablesFlagsSettings { bool* m_pShowTimestamp = nullptr; bool* m_pShowServerTimestamp = nullptr; bool* m_pCreateNoncanonicalKeys = nullptr; + std::unique_ptr m_pOrdering; // NetworkTablesOrdering int* m_pPrecision = nullptr; NetworkTablesFlags m_defaultFlags; // NOLINT NetworkTablesFlags m_flags; // NOLINT