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 );
41
42 extern template MRVIEWER_API std::optional<std::int64_t> createValueLow( std::string_view name, std::optional<BoundedValue<std::int64_t>> value );
43 extern template MRVIEWER_API std::optional<std::uint64_t> createValueLow( std::string_view name, std::optional<BoundedValue<std::uint64_t>> value );
44 extern template MRVIEWER_API std::optional<double> createValueLow( std::string_view name, std::optional<BoundedValue<double>> value );
45 extern template MRVIEWER_API std::optional<std::string> createValueLow( std::string_view name, std::optional<BoundedValue<std::string>> value );
46
47 template <typename T>
48 using UnderlyingValueType = std::conditional_t<std::is_floating_point_v<T>, double, std::conditional_t<std::is_signed_v<T>, std::int64_t, std::uint64_t>>;
49}
50
51// Call this every frame when drawing a button you want to track (regardless of whether it returns true of false).
52// If this returns true, simulate a button click.
53[[nodiscard]] MRVIEWER_API bool createButton( std::string_view name );
54
55template <typename T>
56concept AllowedValueType = std::is_arithmetic_v<T> || std::is_same_v<T, std::string>;
57
58// Create a "value" (slider/drag/...).
59// `T` must be a scalar; vector support must be implemented manually.
60// Pass `min >= max` to disable the range checks.
61// If this returns true, use the new value in place of the current one.
62template <AllowedValueType T>
63requires std::is_arithmetic_v<T>
64[[nodiscard]] std::optional<T> createValue( std::string_view name, T value, T min, T max )
65{
66 if ( !( min < max ) )
67 {
68 min = std::numeric_limits<T>::lowest();
69 max = std::numeric_limits<T>::max();
70 }
71
73 static_assert(sizeof(T) <= sizeof(U), "The used type is too large.");
74
75 auto ret = detail::createValueLow<U>( name, detail::BoundedValue<U>{ .value = U( value ), .min = U( min ), .max = U( max ) } );
76 return ret ? std::optional<T>( T( *ret ) ) : std::nullopt;
77}
78// This overload is for strings.
79[[nodiscard]] MRVIEWER_API std::optional<std::string> createValue( std::string_view name, std::string value, std::optional<std::vector<std::string>> allowedValues = std::nullopt );
80
81// Usually you don't need this function.
82// This is for widgets that require you to specify the value override before drawing it, such as `ImGui::CollapsingHeader()`.
83// For those, call this version first to read the value override, then draw the widget, then call the normal `CreateValue()` with the same name
84// and with the new value, and discard its return value.
85template <AllowedValueType T>
86[[nodiscard]] std::optional<T> createValueTentative( std::string_view name )
87{
88 auto ret = detail::createValueLow<detail::UnderlyingValueType<T>>( name, std::nullopt );
89 return ret ? std::optional<T>( T( *ret ) ) : std::nullopt;
90}
91
92// Use those to group buttons into named groups.
93MRVIEWER_API void pushTree( std::string_view name );
94MRVIEWER_API void popTree();
95
96struct Entry;
97
99{
100 // Set this to true to simulate a button click.
101 mutable bool simulateClick = false;
102
103 static constexpr std::string_view kindName = "button";
104};
105
106// For sliders, drags, etc.
108{
109 template <typename T>
110 struct Value
111 {
112 // The current value.
113 T value = 0;
114
115 // Min/max bounds, INCLUSIVE. If none, those are set to the min/max values representable in this type.
116 T min = 0;
117 T max = 0;
118
119 // Set to override the value.
120 mutable std::optional<T> simulatedValue;
121
122 Value() {} // Make `std::variant` below happy.
123 };
124 template <std::same_as<std::string> T> // GCC chokes on full specializations at class scope, hence this.
125 struct Value<T>
126 {
127 // The current value.
128 std::string value;
129
130 std::optional<std::vector<std::string>> allowedValues;
131
132 // Set to override the value.
133 mutable std::optional<std::string> simulatedValue;
134
135 Value() {} // Make `std::variant` below happy.
136 };
137 using ValueVar = std::variant<Value<std::int64_t>, Value<std::uint64_t>, Value<double>, Value<std::string>>;
139
140 static constexpr std::string_view kindName = "value";
141};
142
144{
145 // Using `std::map` over `std::unordered_map` to be able to search by `std::string_view` keys directly.
146 std::map<std::string, Entry, std::less<>> elems;
147
148 static constexpr std::string_view kindName = "group";
149};
150
151struct Entry
152{
153 std::variant<ButtonEntry, ValueEntry, GroupEntry> value;
154
155 // Mostly for internal use.
156 // If this is false, the entry will be removed on the next frame.
157 bool visitedOnThisFrame = false;
158
159 // Returns a string describing the type currently stored in `value`, which is `T::kindName`.
160 [[nodiscard]] MRVIEWER_API std::string_view getKindName() const;
161
162 // Calls `std::get<T>(value)`, returns a user-friendly error on failure.
163 // The returned pointer is never null.
164 // If `selfName` is specified, it's added to the error message as the name of this entry.
165 template <typename T>
166 [[nodiscard]] Expected<T *> getAs( std::string_view selfName = {} )
167 {
168 Expected<T *> ret = std::get_if<T>( &value );
169 if ( !*ret )
170 {
171 if ( selfName.empty() )
172 ret = unexpected( fmt::format( "Expected UI entity to be a `{}` but got a `{}`.", T::kindName, getKindName() ) );
173 else
174 ret = unexpected( fmt::format( "Expected UI entity `{}` to be a `{}` but got a `{}`.", selfName, T::kindName, getKindName() ) );
175 }
176 return ret;
177 }
178 template <typename T>
179 [[nodiscard]] Expected<const T *> getAs( std::string_view selfName = {} ) const
180 {
181 return const_cast<Entry *>( this )->template getAs<T>( selfName );
182 }
183};
184
185// Returns the current entry tree.
186[[nodiscard]] MRVIEWER_API const GroupEntry& getRootEntry();
187
188}
Definition MRUITestEngine.h:56
MRVIEWER_API std::optional< T > createValueLow(std::string_view name, std::optional< BoundedValue< T > > value)
std::conditional_t< std::is_floating_point_v< T >, double, std::conditional_t< std::is_signed_v< T >, std::int64_t, std::uint64_t > > UnderlyingValueType
Definition MRUITestEngine.h:48
Definition MRUITestEngine.h:20
std::optional< T > createValue(std::string_view name, T value, T min, T max)
Definition MRUITestEngine.h:64
MRVIEWER_API bool createButton(std::string_view name)
std::optional< T > createValueTentative(std::string_view name)
Definition MRUITestEngine.h:86
MRVIEWER_API const GroupEntry & getRootEntry()
MRVIEWER_API void popTree()
MRVIEWER_API void pushTree(std::string_view name)
MR_BIND_IGNORE auto unexpected(E &&e)
Definition MRExpected.h:61
tl::expected< T, E > Expected
Definition MRExpected.h:58
Definition MRUITestEngine.h:99
bool simulateClick
Definition MRUITestEngine.h:101
static constexpr std::string_view kindName
Definition MRUITestEngine.h:103
Definition MRUITestEngine.h:152
std::variant< ButtonEntry, ValueEntry, GroupEntry > value
Definition MRUITestEngine.h:153
Expected< const T * > getAs(std::string_view selfName={}) const
Definition MRUITestEngine.h:179
MRVIEWER_API std::string_view getKindName() const
bool visitedOnThisFrame
Definition MRUITestEngine.h:157
Expected< T * > getAs(std::string_view selfName={})
Definition MRUITestEngine.h:166
Definition MRUITestEngine.h:144
static constexpr std::string_view kindName
Definition MRUITestEngine.h:148
std::map< std::string, Entry, std::less<> > elems
Definition MRUITestEngine.h:146
Value()
Definition MRUITestEngine.h:135
std::optional< std::string > simulatedValue
Definition MRUITestEngine.h:133
std::string value
Definition MRUITestEngine.h:128
std::optional< std::vector< std::string > > allowedValues
Definition MRUITestEngine.h:130
Definition MRUITestEngine.h:111
Value()
Definition MRUITestEngine.h:122
T max
Definition MRUITestEngine.h:117
T value
Definition MRUITestEngine.h:113
T min
Definition MRUITestEngine.h:116
std::optional< T > simulatedValue
Definition MRUITestEngine.h:120
Definition MRUITestEngine.h:108
std::variant< Value< std::int64_t >, Value< std::uint64_t >, Value< double >, Value< std::string > > ValueVar
Definition MRUITestEngine.h:137
ValueVar value
Definition MRUITestEngine.h:138
static constexpr std::string_view kindName
Definition MRUITestEngine.h:140
Definition MRUITestEngine.h:26
T min
Definition MRUITestEngine.h:28
T max
Definition MRUITestEngine.h:29
T value
Definition MRUITestEngine.h:27