The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
typed_formula.hpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2008 - 2025
3 by Mark de Wever <koraq@xs4all.nl>
4 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY.
12
13 See the COPYING file for more details.
14*/
15
16#pragma once
17
18#include "color.hpp"
19#include "formula/callable.hpp"
20#include "formula/formula.hpp"
21#include "formula/function.hpp"
22#include "gui/core/log.hpp"
24#include "lexical_cast.hpp"
26#include "tstring.hpp"
27
28#include <cassert>
30
31namespace gui2
32{
33
34/**
35 * Template class can hold a value or a formula to calculate the value.
36 *
37 * A string is a formula when it starts with a right paren, no other validation
38 * is done by this function, leading whitespace is significant.
39 *
40 * Upon getting the value of the formula a variable map is send. The variables
41 * in the map can be used in the formula. The 'owners' of the class need to
42 * document the variables available.
43 *
44 * @tparam T The type of the formula. This type needs to
45 * be constructable form a string, either by a
46 * lexical_cast or a template specialization in
47 * this header.
48 */
49template<typename T>
51{
52public:
53 /**
54 * Constructor.
55 *
56 * @param str The string used to initialize the class, this
57 * can either be a formula or a string which can
58 * be converted to the type T.
59 * @param value The default value for the object.
60 */
61 explicit typed_formula(const std::string& str, const T value = T());
62
63 explicit typed_formula(T value);
64
65 /** Set the value for this object */
66 void set_value(T value) { value_ = value; }
67
68 /**
69 * Returns the value, can only be used if the data is no formula.
70 *
71 * Another option would be to cache the output of the formula in value_
72 * and always allow this function. But for now decided that the caller
73 * needs to do the caching. It might be changed later.
74 */
75 T operator()() const
76 {
77 assert(!has_formula());
78 return value_;
79 }
80
81 /**
82 * Returns the value, can always be used.
83 *
84 * @param variables The state variables which might be used in
85 * the formula. For example, screen_width can
86 * be set so the formula can return the half
87 * width of the screen.
88 *
89 * @param functions The variables, which can be called during the
90 * evaluation of the formula. (Note it is also
91 * possible to add extra functions to the table,
92 * when the variable is not @c nullptr.
93 *
94 * @returns The stored result or the result of the
95 * evaluation of the formula.
96 */
98 wfl::function_symbol_table* functions = nullptr) const;
99
100 /** Determine whether the class contains a formula. */
101 bool has_formula() const
102 {
103 return formula_.has_value();
104 }
105
106private:
107 /**
108 * Converts the string to the template type.
109 *
110 * This function is used by the constructor to convert the string to the
111 * wanted value, if not a formula.
112 *
113 * @param str The str send to the constructor.
114 */
115 void convert(const std::string& str);
116
117 /**
118 * Executes the formula.
119 *
120 * This function does the calculation and can only be called if the object
121 * contains a formula.
122 *
123 * @param v A variant object containing the evaluated value
124 * of the formula.
125 *
126 * @returns The calculated value.
127 */
129
130 /**
131 * Contains the formula for the variable.
132 *
133 * If without value, there's no formula.
134 */
135 utils::optional<std::string> formula_;
136
137 /** If there's no formula it contains the value. */
139};
140
141template<typename T>
142typed_formula<T>::typed_formula(const std::string& str, const T value)
143 : formula_(), value_(value)
144{
145 if(str.empty()) {
146 return;
147 }
148
149 if(str[0] == '(') {
150 formula_ = str;
151 } else {
152 convert(str);
153 }
154}
155
156template<typename T>
158 : formula_(), value_(value)
159{
160}
161
162template<typename T>
164operator()(const wfl::map_formula_callable& variables, wfl::function_symbol_table* functions) const
165{
166 if(!has_formula()) {
167 return value_;
168 }
169
170 wfl::variant v = wfl::formula(*formula_, functions).evaluate(variables);
171 const T& result = execute(v);
172
173 DBG_GUI_D << "Formula: execute '" << *formula_ << "' result '" << result << "'.";
174
175 return result;
176}
177
178/**
179 * Template specializations.
180 *
181 * Each type must have an @ref execute specialization, and optionally one for @ref convert.
182 */
183
184template<>
186{
187 return v.as_bool();
188}
189
190template<>
191inline void typed_formula<bool>::convert(const std::string& str)
192{
194}
195
196
197template<>
199{
200 return v.as_int();
201}
202
203
204template<>
206{
207 // FIXME: Validate this? As is, the formula could return a negative number which is blindly converted to unsigned.
208 // Unfortunately, some places rely on this happening for diagnostic messages...
209 return v.as_int();
210}
211
212
213template<>
215{
216 return v.as_string();
217}
218
219template<>
220inline void typed_formula<std::string>::convert(const std::string& str)
221{
222 value_ = str;
223}
224
225
226template<>
228{
229 return v.as_string();
230}
231
232template<>
233inline void typed_formula<t_string>::convert(const std::string& str)
234{
235 value_ = str;
236}
237
238
239template<>
241{
243}
244
245template<>
246inline void typed_formula<PangoAlignment>::convert(const std::string& str)
247{
249}
250
251
252template<>
254{
255 const auto& result = v.as_list();
256 const int alpha = result.size() == 4 ? result[3].as_int() : ALPHA_OPAQUE;
257
258 return color_t(
259 result.at(0).as_int(),
260 result.at(1).as_int(),
261 result.at(2).as_int(),
262 alpha
263 );
264}
265
266template<>
267inline void typed_formula<color_t>::convert(const std::string& str)
268{
270}
271
272
273template<typename T>
275{
276 // Every type needs its own execute function avoid instantiation of the
277 // default execute.
278 static_assert(sizeof(T) == 0, "typed_formula: Missing execute specialization");
279 return T();
280}
281
282template<class T>
283inline void typed_formula<T>::convert(const std::string& str)
284{
285 value_ = lexical_cast_default<T>(str);
286}
287
288} // namespace gui2
std::unique_ptr< PangoAttribute, void(*)(PangoAttribute *)> value_
Template class can hold a value or a formula to calculate the value.
bool has_formula() const
Determine whether the class contains a formula.
typed_formula(const std::string &str, const T value=T())
Constructor.
utils::optional< std::string > formula_
Contains the formula for the variable.
void convert(const std::string &str)
Converts the string to the template type.
T value_
If there's no formula it contains the value.
T operator()() const
Returns the value, can only be used if the data is no formula.
T execute(wfl::variant &v) const
Executes the formula.
void set_value(T value)
Set the value for this object.
T operator()(const wfl::map_formula_callable &variables, wfl::function_symbol_table *functions=nullptr) const
Returns the value, can always be used.
static variant evaluate(const const_formula_ptr &f, const formula_callable &variables, formula_debugger *fdb=nullptr, variant default_res=variant(0))
Definition formula.hpp:48
int as_int(int fallback=0) const
Returns the variant's value as an integer.
Definition variant.cpp:336
const std::string & as_string() const
Definition variant.cpp:362
bool as_bool() const
Returns a boolean state of the variant value.
Definition variant.cpp:357
const std::vector< variant > & as_list() const
Definition variant.cpp:367
constexpr uint8_t ALPHA_OPAQUE
Definition color.hpp:37
Define the common log macros for the gui toolkit.
#define DBG_GUI_D
Definition log.hpp:29
New lexcical_cast header.
Generic file dialog.
PangoAlignment decode_text_alignment(const std::string &alignment)
Converts a text alignment string to a text alignment.
Definition helper.cpp:84
bool string_bool(const std::string &str, bool def)
Convert no, false, off, 0, 0.0 to false, empty to def, and others to true.
std::unique_ptr< MIX_Audio, decltype(&MIX_DestroyAudio)> value
Definition sound.cpp:139
The basic class for representing 8-bit RGB or RGBA colour values.
Definition color.hpp:51
static color_t from_rgba_string(std::string_view c)
Creates a new color_t object from a string variable in "R,G,B,A" format.
Definition color.cpp:23