HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
observable.hpp
1// Copyright 2020 Pokitec
2// All rights reserved.
3
4#pragma once
5
6#include "TTauri/Foundation/notifier.hpp"
7#include "TTauri/Foundation/hires_utc_clock.hpp"
8#include "TTauri/Foundation/numeric_cast.hpp"
9#include "TTauri/Foundation/notifier.hpp"
10#include "detail/observable_value.hpp"
11#include "detail/observable_not.hpp"
12#include "detail/observable_cast.hpp"
13#include <memory>
14#include <functional>
15#include <algorithm>
16
17namespace tt {
18
19template<typename T>
21public:
22 using value_type = T;
23 using callback_type = std::function<void(value_type const &)>;
26
27private:
29
31 size_t pimpl_cbid;
32
34 pimpl(value)
35 {
36 pimpl_cbid = pimpl->add_callback([this](ttlet &tmp) {
37 this->notifier(tmp);
38 });
39 }
40
42 pimpl(std::move(value))
43 {
44 pimpl_cbid = pimpl->add_callback([this](ttlet &tmp) {
45 this->notifier(tmp);
46 });
47 }
48
49 observable &operator=(std::shared_ptr<detail::observable_base<value_type>> const &value) noexcept {
50 pimpl->remove_callback(pimpl_cbid);
51
52 pimpl = value;
53
54 pimpl_cbid = pimpl->add_callback([this](ttlet &tmp) {
55 this->notifier(tmp);
56 });
57
58 return *this;
59 }
60
61public:
62 observable(observable const &other) noexcept :
63 pimpl(other.pimpl)
64 {
65 pimpl_cbid = pimpl->add_callback([this](ttlet &tmp) {
66 this->notifier(tmp);
67 });
68 }
69
70 observable &operator=(observable const &other) noexcept
71 {
72 pimpl->remove_callback(pimpl_cbid);
73 pimpl = other.pimpl;
74 pimpl_cbid = pimpl->add_callback([this](ttlet &tmp) {
75 this->notifier(tmp);
76 });
77 return *this;
78 }
79
80 // Use the copy constructor and assignment operator.
81 //observable(observable &&other) noexcept = delete;
82 //observable &operator=(observable &&other) noexcept = delete;
83
84 ~observable() {
85 tt_assume(pimpl);
86 pimpl->remove_callback(pimpl_cbid);
87 }
88
89 observable() noexcept :
92 )) {}
93
94 observable(value_type const &value) noexcept :
97 )) {}
98
99 template<typename Other>
100 observable(observable<Other> const &other) noexcept :
103 )) {}
104
105 template<typename Other>
106 observable(Other const &other) noexcept :
111 )
112 )
113 ) {}
114
115 observable &operator=(value_type const &value) noexcept {
116 store(value);
117 return *this;
118 }
119
120 template<typename Other>
121 observable &operator=(observable<Other> const &other) noexcept {
122 return *this = std::static_pointer_cast<detail::observable_base<value_type>>(
123 std::make_shared<detail::observable_cast<value_type,Other>>(other.pimpl)
124 );
125 }
126
127 template<typename Other>
128 observable &operator=(Other const &other) noexcept {
129 return *this = std::static_pointer_cast<detail::observable_base<value_type>>(
130 std::make_shared<detail::observable_cast<value_type,Other>>(
131 std::make_shared<detail::observable_value<Other>>(other)
132 )
133 );
134 }
135
136 [[nodiscard]] value_type previous_value() const noexcept {
137 tt_assume(pimpl);
138 return pimpl->previous_value();
139 }
140
143 [[nodiscard]] time_point time_when_last_modified() const noexcept {
144 tt_assume(pimpl);
145 return pimpl->time_when_last_modified();
146 }
147
150 [[nodiscard]] duration duration_since_last_modified() const noexcept {
151 tt_assume(pimpl);
152 return pimpl->duration_since_last_modified();
153 }
154
160 [[nodiscard]] float animation_progress(duration animation_duration) const noexcept {
161 tt_assume(pimpl);
162 return pimpl->animation_progress(animation_duration);
163 }
164
165 [[nodiscard]] bool animating(duration animation_duration) const noexcept {
166 tt_assume(pimpl);
167 return pimpl->animation_progress(animation_duration) < 1.0f;
168 }
169
170 [[nodiscard]] value_type load() const noexcept {
171 tt_assume(pimpl);
172 return pimpl->load();
173 }
174
175 [[nodiscard]] value_type operator*() const noexcept {
176 tt_assume(pimpl);
177 return pimpl->load();
178 }
179
180 [[nodiscard]] value_type load(duration animation_duration) const noexcept {
181 tt_assume(pimpl);
182 return pimpl->load(animation_duration);
183 }
184
185 bool store(value_type const &new_value) noexcept {
186 tt_assume(pimpl);
187 return pimpl->store(new_value);
188 }
189
190 [[nodiscard]] size_t add_callback(callback_type callback) noexcept {
191 return notifier.add(callback);
192 }
193
194 void remove_callback(size_t id) noexcept {
195 return notifier.remove(id);
196 }
197
198 [[nodiscard]] friend observable<bool> operator!(observable const &rhs) noexcept {
199 return std::static_pointer_cast<detail::observable_base<bool>>(
200 std::make_shared<detail::observable_not<bool>>(rhs.pimpl)
201 );
202 }
203
204 [[nodiscard]] friend bool operator==(observable const &lhs, observable const &rhs) noexcept {
205 return *lhs == *rhs;
206 }
207
208 [[nodiscard]] friend bool operator==(observable const &lhs, value_type const &rhs) noexcept {
209 return *lhs == rhs;
210 }
211
212 [[nodiscard]] friend bool operator==(value_type const &lhs, observable const &rhs) noexcept {
213 return lhs == *rhs;
214 }
215
216 [[nodiscard]] friend bool operator!=(observable const &lhs, observable const &rhs) noexcept {
217 return *lhs != *rhs;
218 }
219
220 [[nodiscard]] friend bool operator!=(observable const &lhs, value_type const &rhs) noexcept {
221 return *lhs != rhs;
222 }
223
224 [[nodiscard]] friend bool operator!=(value_type const &lhs, observable const &rhs) noexcept {
225 return lhs != *rhs;
226 }
227
228 [[nodiscard]] friend float to_float(observable const &rhs) noexcept {
229 return numeric_cast<float>(rhs.load());
230 }
231
232 [[nodiscard]] friend float to_float(observable const &rhs, duration animation_duration) noexcept {
233 ttlet previous_value = numeric_cast<float>(rhs.previous_value());
234 ttlet current_value = numeric_cast<float>(rhs.load());
235 ttlet animation_progress = rhs.animation_progress(animation_duration);
236 return mix(animation_progress, previous_value, current_value);
237 }
238
239 [[nodiscard]] friend std::string to_string(observable const &rhs) noexcept {
240 return to_string(rhs.load());
241 }
242
243 friend std::ostream &operator<<(std::ostream &lhs, observable const &rhs) noexcept {
244 return lhs << rhs.load();
245 }
246
247};
248
249}
250
Observable abstract base class.
Definition observable_base.hpp:29
Definition observable_cast.hpp:11
Definition observable_value.hpp:11
A notifier which can be used to call a set of registred callbacks.
Definition notifier.hpp:21
void remove(size_t id) noexcept
Remove a callback from the notifier.
Definition notifier.hpp:65
size_t add(callback_type callback) noexcept
Add a callback to the notifier.
Definition notifier.hpp:36
Definition observable.hpp:20
duration duration_since_last_modified() const noexcept
Duration since the value was last modified.
Definition observable.hpp:150
float animation_progress(duration animation_duration) const noexcept
The relative time since the start of the animation.
Definition observable.hpp:160
time_point time_when_last_modified() const noexcept
Time when the value was modified last.
Definition observable.hpp:143
T make_shared(T... args)
T move(T... args)
T static_pointer_cast(T... args)