From 1e7466edf2a644b3376c2eb00408b2171ae43010 Mon Sep 17 00:00:00 2001 From: Fredrik Lindahl Date: Sun, 17 Nov 2024 11:27:00 +0100 Subject: [PATCH] Added tooltips and hideInInspector option to NIDL and inspectors --- .../audiofeature/components/audiofeature.json | 23 ++++---- .../components/graphicsfeature.json | 18 ++++-- .../components/physicsfeature.json | 3 +- .../basegamefeature/components/orientation.h | 12 ++++ .../basegamefeature/components/position.h | 10 ++++ .../basegamefeature/components/scale.h | 10 ++++ .../basegamefeature/components/velocity.h | 20 +++++++ code/application/game/componentinspection.cc | 9 ++- code/application/game/componentinspection.h | 56 ++++++++++++------- fips-files/generators/IDLC/idlcomponent.py | 43 +++++++++++++- fips-files/generators/NIDL.py | 2 +- 11 files changed, 163 insertions(+), 43 deletions(-) diff --git a/code/addons/audiofeature/components/audiofeature.json b/code/addons/audiofeature/components/audiofeature.json index 43826e3df..c034e2db4 100644 --- a/code/addons/audiofeature/components/audiofeature.json +++ b/code/addons/audiofeature/components/audiofeature.json @@ -13,56 +13,57 @@ "clipResource": { "type": "resource", "default": "audio:system/placeholder.wav", - "desc": "The audio clip to load upon activation" + "description": "The audio clip to load upon activation" }, "clipId": { "type": "uint", "default": -1, - "desc": "The Audio::ClipId for this emitter." + "description": "The Audio::ClipId for this emitter.", + "hideInInspector": true }, "volume": { "type": "float", "default": 1.0, - "desc": "Max volume" + "description": "Max volume" }, "autoplay": { "type": "bool", - "desc": "Set to true if the emitter should start immediately upon creation" + "description": "Set to true if the emitter should start immediately upon creation" }, "pan": { "type": "float", "default": 0.0, - "desc": "2D pan for non spatialized sounds. (L = -1.0, R = 1.0)" + "description": "2D pan for non spatialized sounds. (L = -1.0, R = 1.0)" }, "loop": { "type": "bool", - "desc": "Set to true if the emitter should loop after reaching the end of the clip" + "description": "Set to true if the emitter should loop after reaching the end of the clip" }, "clock": { "type": "float", "default": 0.0, - "desc": "Set this to > 0 if you need to delay the start of sounds so that rapidly launched sounds don't all get clumped to the start of the next outgoing sound buffer." + "description": "Set this to > 0 if you need to delay the start of sounds so that rapidly launched sounds don't all get clumped to the start of the next outgoing sound buffer." } }, "SpatialAudioEmission": { "minDistance": { "type": "float", "default": 0.0, - "desc": "Minimum audible distance of the sound" + "description": "Minimum audible distance of the sound" }, "maxDistance": { "type": "float", "default": 10000.0, - "desc": "Maximum audible distance of the sound" + "description": "Maximum audible distance of the sound" }, "attenuation": { "type": "AudioFeature::AttenuationModel", "default": 1, - "desc": "The attenuation model to use" + "description": "The attenuation model to use" } }, "ClipInstance": { - "id": "uint" + "id": "uint", }, "PlayAudioEvent": {}, "AudioListener": {}, diff --git a/code/addons/graphicsfeature/components/graphicsfeature.json b/code/addons/graphicsfeature/components/graphicsfeature.json index 1819babc5..d6ceaed57 100644 --- a/code/addons/graphicsfeature/components/graphicsfeature.json +++ b/code/addons/graphicsfeature/components/graphicsfeature.json @@ -15,7 +15,8 @@ "PointLight": { "graphicsEntityId": { "type": "uint", - "default": -1 + "default": -1, + "hideInInspector": true }, "color": { "type": "color", @@ -34,7 +35,8 @@ "SpotLight": { "graphicsEntityId": { "type": "uint", - "default": -1 + "default": -1, + "hideInInspector": true }, "color": { "type": "color", @@ -61,7 +63,8 @@ "AreaLight": { "graphicsEntityId": { "type": "uint", - "default": -1 + "default": -1, + "hideInInspector": true }, "shape": { "type": "GraphicsFeature::AreaLightShape", @@ -90,7 +93,8 @@ }, "graphicsEntityId": { "type": "uint", - "default": -1 + "default": -1, + "hideInInspector": true }, "raytracing": "bool", "anim": { @@ -105,10 +109,12 @@ "Camera": { "viewHandle": { "type": "uint", - "default": -1 + "default": -1, + "hideInInspector": true }, "localTransform": { - "type": "mat4" + "type": "mat4", + "hideInInspector": true }, "fieldOfView": { "type": "float", diff --git a/code/addons/physicsfeature/components/physicsfeature.json b/code/addons/physicsfeature/components/physicsfeature.json index 57cd824af..b7732637f 100644 --- a/code/addons/physicsfeature/components/physicsfeature.json +++ b/code/addons/physicsfeature/components/physicsfeature.json @@ -15,7 +15,8 @@ "PhysicsActor": { "actorId": { "type": "uint", - "default": -1 + "default": -1, + "hideInInspector": true }, "resource": { "type": "resource", diff --git a/code/application/basegamefeature/components/orientation.h b/code/application/basegamefeature/components/orientation.h index 6d5df2efe..f6e3ab5c4 100644 --- a/code/application/basegamefeature/components/orientation.h +++ b/code/application/basegamefeature/components/orientation.h @@ -47,6 +47,12 @@ struct Orientation::Traits "float", "float" }; + static constexpr const char* field_descriptions[num_fields] = { + nullptr, + nullptr, + nullptr, + nullptr + }; using field_types = std::tuple; static constexpr size_t field_byte_offsets[num_fields] = { offsetof(Orientation, x), @@ -54,6 +60,12 @@ struct Orientation::Traits offsetof(Orientation, z), offsetof(Orientation, w), }; + static constexpr bool field_hide_in_inspector[num_fields] = { + false, + false, + false, + false + }; /// This is the column that the entity orientation will reside in, in every table. /// NOTE: This can never be changed, due to assumptions that have been made. static constexpr uint32_t fixed_column_index = 2; diff --git a/code/application/basegamefeature/components/position.h b/code/application/basegamefeature/components/position.h index 307c05e12..df5211293 100644 --- a/code/application/basegamefeature/components/position.h +++ b/code/application/basegamefeature/components/position.h @@ -46,12 +46,22 @@ struct Position::Traits "float", "float" }; + static constexpr const char* field_descriptions[num_fields] = { + nullptr, + nullptr, + nullptr + }; using field_types = std::tuple; static constexpr size_t field_byte_offsets[num_fields] = { offsetof(Position, x), offsetof(Position, y), offsetof(Position, z) }; + static constexpr bool field_hide_in_inspector[num_fields] = { + false, + false, + false + }; /// This is the column that the entity position will reside in, in every table. /// NOTE: This can never be changed, due to assumptions that have been made. static constexpr uint32_t fixed_column_index = 1; diff --git a/code/application/basegamefeature/components/scale.h b/code/application/basegamefeature/components/scale.h index af64002e3..d937daa07 100644 --- a/code/application/basegamefeature/components/scale.h +++ b/code/application/basegamefeature/components/scale.h @@ -49,12 +49,22 @@ struct Scale::Traits "float", "float" }; + static constexpr const char* field_descriptions[num_fields] = { + nullptr, + nullptr, + nullptr + }; using field_types = std::tuple; static constexpr size_t field_byte_offsets[num_fields] = { offsetof(Scale, x), offsetof(Scale, y), offsetof(Scale, z) }; + static constexpr bool field_hide_in_inspector[num_fields] = { + false, + false, + false + }; /// This is the column that the entity scale will reside in, in every table. /// NOTE: This can never be changed, due to assumptions that have been made. static constexpr uint32_t fixed_column_index = 3; diff --git a/code/application/basegamefeature/components/velocity.h b/code/application/basegamefeature/components/velocity.h index e098437e2..df6e3032f 100644 --- a/code/application/basegamefeature/components/velocity.h +++ b/code/application/basegamefeature/components/velocity.h @@ -56,12 +56,22 @@ struct Velocity::Traits "float", "float" }; + static constexpr const char* field_descriptions[num_fields] = { + nullptr, + nullptr, + nullptr + }; using field_types = std::tuple; static constexpr size_t field_byte_offsets[num_fields] = { offsetof(Velocity, x), offsetof(Velocity, y), offsetof(Velocity, z) }; + static constexpr bool field_hide_in_inspector[num_fields] = { + false, + false, + false + }; }; //------------------------------------------------------------------------------ @@ -84,12 +94,22 @@ struct AngularVelocity::Traits "float", "float" }; + static constexpr const char* field_descriptions[num_fields] = { + nullptr, + nullptr, + nullptr + }; using field_types = std::tuple; static constexpr size_t field_byte_offsets[num_fields] = { offsetof(AngularVelocity, x), offsetof(AngularVelocity, y), offsetof(AngularVelocity, z) }; + static constexpr bool field_hide_in_inspector[num_fields] = { + false, + false, + false + }; }; } // namespace Game diff --git a/code/application/game/componentinspection.cc b/code/application/game/componentinspection.cc index 86d9dd4ee..fda6cbe18 100644 --- a/code/application/game/componentinspection.cc +++ b/code/application/game/componentinspection.cc @@ -200,7 +200,14 @@ void ComponentDrawFuncT(ComponentId component, void* data, bool* commit) { ImGui::PushID(component.id + 0x125233 + reinterpret_cast(data)); - ImGui::Text(((Util::StringAtom*)data)->Value()); + if (((Util::StringAtom*)data)->IsValid()) + { + ImGui::Text(((Util::StringAtom*)data)->Value()); + } + else + { + ImGui::Text("None"); + } if (ImGui::BeginDragDropTarget()) { auto payload = ImGui::AcceptDragDropPayload("resource"); diff --git a/code/application/game/componentinspection.h b/code/application/game/componentinspection.h index f4ffc731c..1c7136ef6 100644 --- a/code/application/game/componentinspection.h +++ b/code/application/game/componentinspection.h @@ -56,29 +56,45 @@ InspectorDrawField(ComponentId component, void* data, bool* commit) { if constexpr (i < TYPE::Traits::num_fields) { - using field_tuple = typename TYPE::Traits::field_types; - using field_type = typename std::tuple_element::type; - Util::String fieldName = TYPE::Traits::field_names[i]; - fieldName.CamelCaseToWords(); - fieldName.Capitalize(); - ImGui::TableSetColumnIndex(0); - ImGui::AlignTextToFramePadding(); - ImGui::Text(fieldName.AsCharPtr()); - ImGui::TableSetColumnIndex(1); - ComponentDrawFuncT(component, (byte*)data + TYPE::Traits::field_byte_offsets[i], commit); - - ImGui::SameLine(); - ImGuiStyle const& style = ImGui::GetStyle(); - float widthNeeded = ImGui::CalcTextSize(TYPE::Traits::field_typenames[i]).x + style.FramePadding.x * 2.f + style.ItemSpacing.x; - ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - widthNeeded); - ImGui::AlignTextToFramePadding(); - ImGui::TextDisabled(TYPE::Traits::field_typenames[i]); - - if constexpr (i < TYPE::Traits::num_fields - 1) + if constexpr (TYPE::Traits::field_hide_in_inspector[i]) { - ImGui::TableNextRow(); + // Just move to the next field InspectorDrawField(component, data, commit); } + else + { + using field_tuple = typename TYPE::Traits::field_types; + using field_type = typename std::tuple_element::type; + Util::String fieldName = TYPE::Traits::field_names[i]; + fieldName.CamelCaseToWords(); + fieldName.Capitalize(); + ImGui::TableSetColumnIndex(0); + ImGui::AlignTextToFramePadding(); + ImGui::Text(fieldName.AsCharPtr()); + if (TYPE::Traits::field_descriptions[i] != nullptr) + { + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) + { + ImGui::SetTooltip(TYPE::Traits::field_descriptions[i]); + } + } + ImGui::TableSetColumnIndex(1); + ComponentDrawFuncT(component, (byte*)data + TYPE::Traits::field_byte_offsets[i], commit); + + ImGui::SameLine(); + ImGuiStyle const& style = ImGui::GetStyle(); + float widthNeeded = + ImGui::CalcTextSize(TYPE::Traits::field_typenames[i]).x + style.FramePadding.x * 2.f + style.ItemSpacing.x; + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - widthNeeded); + ImGui::AlignTextToFramePadding(); + ImGui::TextDisabled(TYPE::Traits::field_typenames[i]); + + if constexpr (i < TYPE::Traits::num_fields - 1) + { + ImGui::TableNextRow(); + InspectorDrawField(component, data, commit); + } + } } } diff --git a/fips-files/generators/IDLC/idlcomponent.py b/fips-files/generators/IDLC/idlcomponent.py index 34307f0fe..3171025b8 100644 --- a/fips-files/generators/IDLC/idlcomponent.py +++ b/fips-files/generators/IDLC/idlcomponent.py @@ -9,12 +9,19 @@ ## # class VariableDefinition: - def __init__(self, T, name, defVal): + def __init__(self, T, name: str, defVal, hideInInspector: bool, description: str): if not isinstance(T, str) and T is not None: util.fmtError('"type" value is not a string value!') self.type = T if not isinstance(name, str): util.fmtError('"name" value is not a string value!') + if not isinstance(hideInInspector, bool): + util.fmtError('"hideInInspector" value is not a bool value!') + if not isinstance(description, str): + util.fmtError('"description" value is not a string value!') + + self.description = description + self.hideInInspector = hideInInspector self.name = name self.defaultValue = defVal @@ -81,15 +88,23 @@ def GetVariableFromEntry(name, var): util.fmtError('{} : {}'.format(name, var.__repr__())) default = None + hideInInspector = False + description = "" if "default" in var: default = IDLTypes.GetCppTypeString(var["type"]) + "(" + IDLTypes.DefaultToString(var["default"]) + ")" else: default = IDLTypes.DefaultValue(var["type"]) - return VariableDefinition(var["type"], name, default) + if "hideInInspector" in var: + hideInInspector = var["hideInInspector"] + + if "description" in var: + description = var["description"] + + return VariableDefinition(var["type"], name, default, hideInInspector, description) else: - return VariableDefinition(var, name, IDLTypes.DefaultValue(var)) + return VariableDefinition(var, name, IDLTypes.DefaultValue(var), False, "") #------------------------------------------------------------------------------ ## @@ -173,10 +188,32 @@ def WriteComponentHeaderDeclarations(f, document): for v in c.variables: f.WriteLine(' offsetof({}, {}),'.format(c.componentName, v.name)) f.WriteLine('};') + f.WriteLine('static constexpr const char* field_descriptions[num_fields] = {') + for i, v in enumerate(c.variables): + if not v.description: + f.Write(' nullptr') + else: + f.Write(' "{}"'.format(v.description)) + if i < (len(c.variables) - 1): + f.WriteLine(",") + else: + f.WriteLine("") + f.WriteLine('};') + f.WriteLine('static constexpr bool field_hide_in_inspector[num_fields] = {') + for i, v in enumerate(c.variables): + f.Write(' {}'.format("true" if v.hideInInspector else "false")) + if i < (len(c.variables) - 1): + f.WriteLine(",") + else: + f.WriteLine("") + f.WriteLine('};') else: f.WriteLine('static constexpr const char** field_names = nullptr;') f.WriteLine('static constexpr const char** field_typenames = nullptr;') f.WriteLine('static constexpr size_t* field_byte_offsets = nullptr;') + f.WriteLine('static constexpr const char** field_descriptions = nullptr;') + f.WriteLine('static constexpr bool* field_hide_in_inspector = nullptr;') + diff --git a/fips-files/generators/NIDL.py b/fips-files/generators/NIDL.py index 60b8b555a..55cdd5953 100644 --- a/fips-files/generators/NIDL.py +++ b/fips-files/generators/NIDL.py @@ -1,4 +1,4 @@ -Version = 147 +Version = 149 import sys if __name__ == '__main__':