MeshLib C++ Docs
Loading...
Searching...
No Matches
MRUITestEngine.h
Go to the documentation of this file.
1#pragma once
2
3#include "MRMesh/MRExpected.h"
4#include "MRPch/MRFmt.h"
5#include "MRViewer/exports.h"
6
7#include <cstdint>
8#include <limits>
9#include <map>
10#include <optional>
11#include <string_view>
12#include <string>
13#include <variant>
14#include <vector>
15
16// This is a low-level header for implementing GUIs that can be interacted with programmatically.
17// Most likely you don't need to touch this, just use widgets from `MRUIStyle.h`.
18
20{
21
22namespace detail
23{
24 template <typename T>
26 {
27 T value{};
28 T min{};
29 T max{};
30 };
31 template <>
32 struct BoundedValue<std::string>
33 {
34 std::string value;
35
36 std::optional<std::vector<std::string>> allowedValues;
37 };
38
39 template <typename T>
40 [[nodiscard]] MRVIEWER_API std::optional<T> createValueLow( std::string_view name, std::optional<BoundedValue<T>> value, bool consumeValueOverride = true );
41
42 extern template MRVIEWER_API std::optional<std::int64_t> createValueLow( std::string_view name, std::optional<BoundedValue<std::int64_t>> value, bool consumeValueOverride );
43 extern template MRVIEWER_API std::optional<std::uint64_t> createValueLow( std::string_view name, std::optional<BoundedValue<std::uint64_t>> value, bool consumeValueOverride );
44 extern template MRVIEWER_API std::optional<double> createValueLow( std::string_view name, std::optional<BoundedValue<double>> value, bool consumeValueOverride );
45 extern template MRVIEWER_API std::optional<std::string> createValueLow( std::string_view name, std::optional<BoundedValue<std::string>> value, bool consumeValueOverride );
46
47 template <typename T, typename = void> struct UnderlyingValueTypeHelper {};
48 template <typename T> struct UnderlyingValueTypeHelper<T, std::enable_if_t<std::is_floating_point_v<T>>> {using type = double;};
49 template <typename T> struct UnderlyingValueTypeHelper<T, std::enable_if_t<std::is_integral_v<T> && std::is_signed_v<T>>> {using type = std::int64_t;};
50 template <typename T> struct UnderlyingValueTypeHelper<T, std::enable_if_t<std::is_integral_v<T> && std::is_unsigned_v<T>>> {using type = std::uint64_t;};
51 template <> struct UnderlyingValueTypeHelper<std::string> {using type = std::string;};
52
53 template <typename T>
55}
56
57// Call this every frame when drawing a button you want to track (regardless of whether it returns true of false).
58// If this returns true, simulate a button click.
59[[nodiscard]] MRVIEWER_API bool createButton( std::string_view name );
60
61template <typename T>
62concept AllowedValueType = std::is_arithmetic_v<T> || std::is_same_v<T, std::string>;
63
64// Create a "value" (slider/drag/...).
65// `T` must be a scalar; vector support must be implemented manually.
66// Pass `min >= max` to disable the range checks.
67// If this returns true, use the new value in place of the current one.
68// \param consumeValueOverride If true - retrieves (deletes) a value from storage.
69// If false - copies the value from the storage (saves the original to the storage to be retrieved again, for example, in the next frame)
70template <AllowedValueType T>
71requires std::is_arithmetic_v<T>
72[[nodiscard]] std::optional<T> createValue( std::string_view name, T value, T min, T max, bool consumeValueOverride = true )
73{
74 if ( !( min < max ) )
75 {
76 min = std::numeric_limits<T>::lowest();
77 max = std::numeric_limits<T>::max();
78 }
79
81 static_assert(sizeof(T) <= sizeof(U), "The used type is too large.");
82
83 auto ret = detail::createValueLow<U>( name, detail::BoundedValue<U>{ .value = U( value ), .min = U( min ), .max = U( max ) }, consumeValueOverride );
84 return ret ? std::optional<T>( T( *ret ) ) : std::nullopt;
85}
86// This overload is for strings.
87[[nodiscard]] MRVIEWER_API std::optional<std::string> createValue( std::string_view name, std::string value, bool consumeValueOverride = true, std::optional<std::vector<std::string>> allowedValues = std::nullopt );
88
89// Usually you don't need this function.
90// This is for widgets that require you to specify the value override before drawing it, such as `ImGui::CollapsingHeader()`.
91// For those, call this version first to read the value override, then draw the widget, then call the normal `CreateValue()` with the same name
92// and with the new value, and discard its return value.
93template <AllowedValueType T>
94[[nodiscard]] std::optional<T> createValueTentative( std::string_view name, bool consumeValueOverride = true )
95{
96 auto ret = detail::createValueLow<detail::UnderlyingValueType<T>>( name, std::nullopt, consumeValueOverride );
97 return ret ? std::optional<T>( T( *ret ) ) : std::nullopt;
98}
99
100// Use those to group buttons into named groups.
101MRVIEWER_API void pushTree( std::string_view name );
102MRVIEWER_API void popTree();
103
104struct Entry;
105
107{
108 // Set this to true to simulate a button click.
109 mutable bool simulateClick = false;
110
111 static constexpr std::string_view kindName = "button";
112};
113
114// For sliders, drags, etc.
116{
117 template <typename T>
118 struct Value
119 {
120 // The current value.
121 T value = 0;
122
123 // Min/max bounds, INCLUSIVE. If none, those are set to the min/max values representable in this type.
124 T min = 0;
125 T max = 0;
126
127 // Set to override the value.
128 mutable std::optional<T> simulatedValue;
129
130 Value() {} // Make `std::variant` below happy.
131 };
132 template <std::same_as<std::string> T> // GCC chokes on full specializations at class scope, hence this.
133 struct Value<T>
134 {
135 // The current value.
136 std::string value;
137
138 std::optional<std::vector<std::string>> allowedValues;
139
140 // Set to override the value.
141 mutable std::optional<std::string> simulatedValue;
142
143 Value() {} // Make `std::variant` below happy.
144 };
145 using ValueVar = std::variant<Value<std::int64_t>, Value<std::uint64_t>, Value<double>, Value<std::string>>;
147
148 static constexpr std::string_view kindName = "value";
149};
150
152{
153 // Using `std::map` over `std::unordered_map` to be able to search by `std::string_view` keys directly.
154 std::map<std::string, Entry, std::less<>> elems;
155
156 static constexpr std::string_view kindName = "group";
157};
158
159struct Entry
160{
161 std::variant<ButtonEntry, ValueEntry, GroupEntry> value;
162
163 // Mostly for internal use.
164 // If this is false, the entry will be removed on the next frame.
165 bool visitedOnThisFrame = false;
166
167 // Returns a string describing the type currently stored in `value`, which is `T::kindName`.
168 [[nodiscard]] MRVIEWER_API std::string_view getKindName() const;
169
170 // Calls `std::get<T>(value)`, returns a user-friendly error on failure.
171 // The returned pointer is never null.
172 // If `selfName` is specified, it's added to the error message as the name of this entry.
173 template <typename T>
174 [[nodiscard]] Expected<T *> getAs( std::string_view selfName = {} )
175 {
176 Expected<T *> ret = std::get_if<T>( &value );
177 if ( !*ret )
178 {
179 if ( selfName.empty() )
180 ret = unexpected( fmt::format( "Expected UI entity to be a `{}` but got a `{}`.", T::kindName, getKindName() ) );
181 else
182 ret = unexpected( fmt::format( "Expected UI entity `{}` to be a `{}` but got a `{}`.", selfName, T::kindName, getKindName() ) );
183 }
184 return ret;
185 }
186 template <typename T>
187 [[nodiscard]] Expected<const T *> getAs( std::string_view selfName = {} ) const
188 {
189 return const_cast<Entry *>( this )->template getAs<T>( selfName );
190 }
191};
192
193// Returns the current entry tree.
194[[nodiscard]] MRVIEWER_API const GroupEntry& getRootEntry();
195
196}
Definition MRUITestEngine.h:62
MRVIEWER_API std::optional< T > createValueLow(std::string_view name, std::optional< BoundedValue< T > > value, bool consumeValueOverride=true)
typename UnderlyingValueTypeHelper< T >::type UnderlyingValueType
Definition MRUITestEngine.h:54
Definition MRUITestEngine.h:20
MRVIEWER_API bool createButton(std::string_view name)
std::optional< T > createValueTentative(std::string_view name, bool consumeValueOverride=true)
Definition MRUITestEngine.h:94
MRVIEWER_API const GroupEntry & getRootEntry()
std::optional< T > createValue(std::string_view name, T value, T min, T max, bool consumeValueOverride=true)
Definition MRUITestEngine.h:72
MRVIEWER_API void popTree()
MRVIEWER_API void pushTree(std::string_view name)
MR_BIND_IGNORE auto unexpected(E &&e)
Definition MRExpected.h:28
tl::expected< T, E > Expected
Definition MRExpected.h:25
Definition MRUITestEngine.h:107
bool simulateClick
Definition MRUITestEngine.h:109
static constexpr std::string_view kindName
Definition MRUITestEngine.h:111
Definition MRUITestEngine.h:160
std::variant< ButtonEntry, ValueEntry, GroupEntry > value
Definition MRUITestEngine.h:161
Expected< const T * > getAs(std::string_view selfName={}) const
Definition MRUITestEngine.h:187
MRVIEWER_API std::string_view getKindName() const
bool visitedOnThisFrame
Definition MRUITestEngine.h:165
Expected< T * > getAs(std::string_view selfName={})
Definition MRUITestEngine.h:174
Definition MRUITestEngine.h:152
static constexpr std::string_view kindName
Definition MRUITestEngine.h:156
std::map< std::string, Entry, std::less<> > elems
Definition MRUITestEngine.h:154
Value()
Definition MRUITestEngine.h:143
std::optional< std::string > simulatedValue
Definition MRUITestEngine.h:141
std::string value
Definition MRUITestEngine.h:136
std::optional< std::vector< std::string > > allowedValues
Definition MRUITestEngine.h:138
Definition MRUITestEngine.h:119
Value()
Definition MRUITestEngine.h:130
T max
Definition MRUITestEngine.h:125
T value
Definition MRUITestEngine.h:121
T min
Definition MRUITestEngine.h:124
std::optional< T > simulatedValue
Definition MRUITestEngine.h:128
Definition MRUITestEngine.h:116
std::variant< Value< std::int64_t >, Value< std::uint64_t >, Value< double >, Value< std::string > > ValueVar
Definition MRUITestEngine.h:145
ValueVar value
Definition MRUITestEngine.h:146
static constexpr std::string_view kindName
Definition MRUITestEngine.h:148
Definition MRUITestEngine.h:26
T min
Definition MRUITestEngine.h:28
T max
Definition MRUITestEngine.h:29
T value
Definition MRUITestEngine.h:27