neoGFX
Cross-platform C++ app/game engine
Loading...
Searching...
No Matches
anchor.hpp
Go to the documentation of this file.
1// anchor.hpp
2/*
3 neogfx C++ App/Game Engine
4 Copyright (c) 2018, 2020 Leigh Johnston. All Rights Reserved.
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 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#pragma once
21
22#include <neogfx/neogfx.hpp>
28
29namespace neogfx
30{
31 template <typename T, typename PVT, class Context, class C, typename... CalculatorArgs>
32 class anchor : public i_calculating_anchor<T, PVT, CalculatorArgs...>
33 {
34 typedef i_calculating_anchor<T, PVT, CalculatorArgs...> base_type;
35 public:
36 using typename base_type::abstract_type;
37 using typename base_type::value_type;
38 using typename base_type::property_value_type;
39 using typename base_type::constraint;
40 typedef Context context_type;
41 private:
42 typedef T(C::* calculator_function_type)(CalculatorArgs...) const;
43 typedef std::pair<constraint, std::shared_ptr<i_anchor>> constraint_entry_t;
44 typedef std::vector<constraint_entry_t> constraint_entries_t;
45 public:
46 anchor(i_anchorable& aOwner, i_property& aProperty) :
47 iOwnerDestroying{ aOwner.as_object() }, iOwner { aOwner }, iProperty{ aProperty }, iCalculating{ false }
48 {
49 iOwner.anchors()[name()] = this;
50 }
51 anchor(i_anchorable& aOwner, i_property& aProperty, calculator_function_type aCalculatorOverride) :
52 iOwnerDestroying{ aOwner.as_object() }, iOwner{ aOwner }, iProperty{ aProperty }, iCalculatorOverride{ aCalculatorOverride }, iCalculating{ false }
53 {
54 iOwner.anchors()[name()] = this;
55 }
57 {
58 if (!iOwnerDestroying)
59 {
60 auto iter = iOwner.anchors().find(name());
61 if (iter != iOwner.anchors().end())
62 iOwner.anchors().erase(iter);
63 }
64 }
65 public:
66 i_anchorable& owner() const override
67 {
68 return iOwner;
69 }
70 const i_string& name() const override
71 {
72 return property().name();
73 }
74 const i_property& property() const override
75 {
76 return iProperty;
77 }
78 i_property& property() override
79 {
80 return iProperty;
81 }
82 bool active() const noexcept override
83 {
84 return !iConstraints.empty();
85 }
86 bool calculator_overriden() const noexcept override
87 {
88 return iCalculatorOverride != std::nullopt;
89 }
90 bool calculating() const noexcept override
91 {
92 return iCalculating;
93 }
94 public:
95 void constrain(i_anchor& aRhs, anchor_constraint_function aLhsFunction, anchor_constraint_function aRhsFunction) override
96 {
97 constrain(aRhs, aRhsFunction);
98 aRhs.constrain(*this, aLhsFunction);
99 }
100 void constrain(i_anchor& aOther, anchor_constraint_function aOtherFunction) override
101 {
102 switch (aOtherFunction)
103 {
105 add_constraint(constraint::identity, static_cast<abstract_type&>(aOther));
106 break;
108 add_constraint(constraint::identity_x, static_cast<abstract_type&>(aOther));
109 break;
111 add_constraint(constraint::identity_y, static_cast<abstract_type&>(aOther));
112 break;
114 add_constraint(constraint::equal, static_cast<abstract_type&>(aOther));
115 break;
117 add_constraint(constraint::equal_x, static_cast<abstract_type&>(aOther));
118 break;
120 add_constraint(constraint::equal_y, static_cast<abstract_type&>(aOther));
121 break;
123 add_constraint(constraint::min, static_cast<abstract_type&>(aOther));
124 break;
126 add_constraint(constraint::min_x, static_cast<abstract_type&>(aOther));
127 break;
129 add_constraint(constraint::min_y, static_cast<abstract_type&>(aOther));
130 break;
132 add_constraint(constraint::max, static_cast<abstract_type&>(aOther));
133 break;
135 add_constraint(constraint::max_x, static_cast<abstract_type&>(aOther));
136 break;
138 add_constraint(constraint::max_y, static_cast<abstract_type&>(aOther));
139 break;
141 // todo
142 break;
143 default:
144 break;
145 }
146 }
147 public:
148 bool property_set() const
149 {
151 return true;
152 else
153 return property().get<property_value_type>() != std::nullopt;
154 }
155 value_type const& property_value() const override
156 {
158 return property().get<property_value_type>();
159 else if (property_set())
160 return *property().get<property_value_type>();
161 else
162 throw anchor_property_has_no_value();
163 }
164 value_type& property_value() override
165 {
166 return const_cast<value_type&>(to_const(*this).property_value());
167 }
168 void add_constraint(constraint const& aConstraint, abstract_type& aOtherAnchor) override
169 {
170 add_constraint(aConstraint, std::shared_ptr<abstract_type>{ std::shared_ptr<abstract_type>{}, &aOtherAnchor });
171 }
172 void add_constraint(constraint const& aConstraint, std::shared_ptr<abstract_type> aOtherAnchor) override
173 {
174 iConstraints.push_back(constraint_entry_t{ aConstraint, aOtherAnchor });
175 }
176 value_type evaluate_constraints(CalculatorArgs const&... aArgs) const override
177 {
178 auto result = calculate(aArgs...);
179 for (auto const& c : iConstraints)
180 {
181 auto const& otherAnchor = static_cast<abstract_type&>(*c.second);
182 result = c.first(result, otherAnchor.calculate(aArgs...));
183 }
184 return result;
185 }
186 value_type calculate(const CalculatorArgs&... aArgs) const override
187 {
188 neolib::scoped_flag sf{ iCalculating };
190 return (static_cast<Context&>(iOwner).**iCalculatorOverride)(aArgs...);
191 else if (property_set())
192 return property_value();
193 else
194 return property().calculate<context_type, calculator_function_type>(aArgs...);
195 }
196 private:
197 destroying_flag iOwnerDestroying;
198 i_anchorable& iOwner;
199 i_property& iProperty;
200 constraint_entries_t iConstraints;
201 std::optional<calculator_function_type> iCalculatorOverride;
202 mutable bool iCalculating;
203 };
204
205 namespace detail
206 {
207 template <template<typename, typename, typename, typename...> class Anchor, class Ctx, typename PVT, typename Callable>
208 struct anchor_callable_function_cracker;
209 template <template<typename, typename, typename, typename...> class Anchor, class Ctx, typename PVT, typename R, typename C, typename... Args>
210 struct anchor_callable_function_cracker<Anchor, Ctx, PVT, R(C::*)(Args...) const>
211 {
212 typedef Anchor<R, PVT, std::add_const_t<Ctx>, C, Args...> type;
213 typedef R(C::* callable_type)(Args...) const;
214 typedef PVT property_value_type;
215 typedef R value_type;
216 typedef C class_type;
217 };
218 template <template<typename, typename, typename, typename...> class Anchor, class Ctx, typename PVT, typename R, typename C, typename... Args>
219 struct anchor_callable_function_cracker<Anchor, Ctx, PVT, R(C::*)(Args...)>
220 {
221 typedef Anchor<R, PVT, Ctx, C, Args...> type;
222 typedef R(C::* callable_type)(Args...);
223 typedef PVT property_value_type;
224 typedef R value_type;
225 typedef C class_type;
226 };
227 }
228
229 template <typename Context, typename PVT, typename Callable>
230 using anchor_t = typename detail::anchor_callable_function_cracker<anchor, Context, PVT, Callable>::type;
231
232 #define define_anchor( name ) neogfx::anchor_t<property_context_type, typename decltype(name)::value_type, typename decltype(name)::calculator_function_type> Anchor_##name = { *this, name };
233 #define define_anchor_ex( name, calculator_override ) neogfx::anchor_t<property_context_type, typename decltype(name)::value_type, typename decltype(name)::calculator_function_type> Anchor_##name = { *this, name, &property_context_type::##calculator_override };
234}
bool active() const noexcept override
Definition anchor.hpp:82
const i_property & property() const override
Definition anchor.hpp:74
anchor(i_anchorable &aOwner, i_property &aProperty, calculator_function_type aCalculatorOverride)
Definition anchor.hpp:51
i_property & property() override
Definition anchor.hpp:78
void constrain(i_anchor &aRhs, anchor_constraint_function aLhsFunction, anchor_constraint_function aRhsFunction) override
Definition anchor.hpp:95
value_type const & property_value() const override
Definition anchor.hpp:155
void add_constraint(constraint const &aConstraint, abstract_type &aOtherAnchor) override
Definition anchor.hpp:168
bool property_set() const
Definition anchor.hpp:148
value_type evaluate_constraints(CalculatorArgs const &... aArgs) const override
Definition anchor.hpp:176
const i_string & name() const override
Definition anchor.hpp:70
void constrain(i_anchor &aOther, anchor_constraint_function aOtherFunction) override
Definition anchor.hpp:100
anchor(i_anchorable &aOwner, i_property &aProperty)
Definition anchor.hpp:46
i_anchorable & owner() const override
Definition anchor.hpp:66
Context context_type
Definition anchor.hpp:40
value_type & property_value() override
Definition anchor.hpp:164
void add_constraint(constraint const &aConstraint, std::shared_ptr< abstract_type > aOtherAnchor) override
Definition anchor.hpp:172
bool calculator_overriden() const noexcept override
Definition anchor.hpp:86
bool calculating() const noexcept override
Definition anchor.hpp:90
value_type calculate(const CalculatorArgs &... aArgs) const override
Definition anchor.hpp:186
virtual const anchor_map_type & anchors() const =0
virtual const i_string & name() const =0
const T & get() const
auto calculate(Args &&... aArgs) const
iterator erase(const abstract_iterator &aPosition)
const_iterator end() const
const_iterator find(const abstract_key_type &aKey) const
Definition i_map.hpp:67
anchor_constraint_function
Definition i_anchor.hpp:31
typename detail::anchor_callable_function_cracker< anchor, Context, PVT, Callable >::type anchor_t
Definition anchor.hpp:230
ref_ptr< ConcreteType > make_ref(Args &&... args)