diff options
author | ancarola <raffaele.ancarola@epfl.ch> | 2019-01-22 03:09:51 +0100 |
---|---|---|
committer | ancarola <raffaele.ancarola@epfl.ch> | 2019-01-22 03:09:51 +0100 |
commit | bd7015d3dd2a3c0df62c552d447dda574543e895 (patch) | |
tree | 5e07ac7a6b6d8df30e2a0fcf47561bf588e4b5cf | |
parent | Sed (diff) | |
download | flatland-bd7015d3dd2a3c0df62c552d447dda574543e895.tar.gz flatland-bd7015d3dd2a3c0df62c552d447dda574543e895.zip |
Woo
-rw-r--r-- | engine/include/signal.h | 112 | ||||
-rw-r--r-- | engine/signal.cpp | 56 | ||||
-rw-r--r-- | test/test3.cpp | 120 |
3 files changed, 271 insertions, 17 deletions
diff --git a/engine/include/signal.h b/engine/include/signal.h new file mode 100644 index 0000000..db6638b --- /dev/null +++ b/engine/include/signal.h @@ -0,0 +1,112 @@ +#pragma once + +#include <map> +#include <list> +#include <set> +#include <initializer_list> +#include "object.hpp" +#include "task.hpp" +#include "types.h" +#include <functional> + +namespace flat +{ + namespace core + { + class signal; + class channel; + } +} + +class flat::core::signal : virtual public flat::core::object +{ + +public: + + flat::core::object * sender; + priority prior; + + signal( flat::core::object * sender, + const std::string& id = "", + priority prior = 5); + + /* Alias to flat::core::channel::emit() */ + bool emit(const std::string& channel) const; + + enum class priority : uint8_t + { + instant = 0, + highest, + high, + none, + low, + lowest + }; +}; + + +/* Channel class */ +class flat::core::channel : virtual public flat::core::object +{ + /* Post processing signal stacking */ + stack_t stack; + + /* Listeners list */ + std::list<flat::core::listener> listeners; + + /* Synchronous task checking for signals */ + task_s * checker; + + /* Channel mapping */ + static std::map<std::string, channel*> channels; + +public: + + flat::core::channel(const std::string& id = "", flat::core::task::priority prior = flat::core::task::priority::none); + ~flat::core::channel(); + + void emit(const flat::core::signal&); + + void connect(flat::core::listener_s*); + void disconnect(flat::core::listener_s*); + + static flat::core::channel * find_channel(const std::string&); + + void post_processing(void*); + + /* Functor for order comparison */ + struct sig_prior_cmp { + + bool operator()(const flat::core::signal&, const flat::core::signal&) const; + }; + + typedef std::set<flat::core::signal, sig_prior_cmp> stack_t; +}; + +/* Listener class */ +class flat::core::listener : virtual public flat::core::object +{ + std::list<std::string> filters; + + bool check_in_filters(const std::string&) const; + + std::function<void(const flat::core::object*)> m_callback; + + flat::core::channel * parent = 0; + +public: + + listener( std::function<void()> m_callback, + const std::initializer_list<std::string>& filters = {}); + + ~listener(); + + void add_filter(const std::string&); + void remove_filter(const std::string&); + + bool connect(const std::string&); + bool disconnect(const std::string&); + + void invoke(const flat::core::signal&); +}; + diff --git a/engine/signal.cpp b/engine/signal.cpp index d20d840..98f133e 100644 --- a/engine/signal.cpp +++ b/engine/signal.cpp @@ -45,33 +45,33 @@ void channel::emit(const signal& sig) if (!sig.priority) { /* Execute immediately */ - for (auto listener_s : listener_ss) - listener_s->execute(sig); + for (auto lis : listeners) + lis->execute(sig); } else /* Insert in order of priority */ stack.insert(sig); } -void channel::connect(listener_s* l) +void channel::connect(listener* l) { /* Control not to double */ - for (auto listener_s : listener_ss) + for (auto lis : listeners) { - if (listener_s == l) + if (lis == l) return; } - listener_ss.push_back(l); + listeners.push_back(l); } -void channel::disconnect(listener_s* l) +void channel::disconnect(listener* l) { - listener_ss.remove(l); + listeners.remove(l); } -channel * channel::findChannel(const string& id) +channel * channel::find_channel(const string& id) { if (id.empty()) return 0; @@ -88,8 +88,8 @@ void channel::post_processing(void*) /* for each listener_s, catch signal */ for (const auto& signal : stack) { - for (auto listener_s : listener_ss) - listener_s->execute(signal); + for (auto l : listeners) + l->execute(signal); } stack.clear(); @@ -123,10 +123,21 @@ bool signal::emit(const string& channel) const /* listener_s class */ -listener_s::listener_s(const initializer_list<string>& filters) - : filters(filters) {} +listener::listener( std::function<void()> m_callback, + const std::initializer_list<std::string>& filters) -bool listener_s::check_in_filters(const std::string& filter) const + : m_callback(m_callback), filters(filters) +{ + +} + +listener::~listener() +{ + if (parent != 0) + parent->disconnect(this); +} + +bool listener::check_in_filters(const std::string& filter) const { for (const auto& f : filters) { @@ -137,23 +148,25 @@ bool listener_s::check_in_filters(const std::string& filter) const return false; } -void listener_s::add_filter(const std::string& f) +void listener::add_filter(const std::string& f) { filters.push_back(f); } -void listener_s::remove_filter(const std::string& f) +void listener::remove_filter(const std::string& f) { filters.remove(f); } -bool listener_s::connect(const std::string& chan) +bool listener::connect(const std::string& chan) { channel * c = channel::find_channel(chan); if (!c) c->connect(this); + parent = c; + return c != 0; } @@ -164,6 +177,15 @@ bool listener_s::disconnect(const std::string& chan) if (!c) c->connect(this); + parent = 0; + return c != 0; } +void listener::invoke(const flat::core::signal&) +{ + if ((!sig.get_id().empty() && check_in_filters(sig.get_id())) || + (sig.get_id().empty() && filters.empty())) + m_callback(sig.sender); +} + diff --git a/test/test3.cpp b/test/test3.cpp new file mode 100644 index 0000000..0edd682 --- /dev/null +++ b/test/test3.cpp @@ -0,0 +1,120 @@ +#include "flatland.h" +#include "flatwindow.h" +#include "exceptions/forcequit.h" + +#include "serial/keyfocusable.h" +#include <SDL2/SDL.h> + +#include <iostream> +#include <string> + +#include "flatsignal.h" + +using namespace std; + +int count = 0; + +void loop(float); + +class KeyPrinter : public KeyFocusable +{ + virtual void key_cb(const SDL_KeyboardEvent* key) override + { + string msg = (key->type == SDL_KEYDOWN) ? "pressed" : "released"; + cout << "KeyPrinter: key " << (char)key->keysym.sym << " " << msg << endl; + }; + +public: + + using KeyFocusable::KeyFocusable; +}; + +class KeyCaller : public KeyFocusable +{ + int counter; + char last; + + virtual void key_cb(const SDL_KeyboardEvent* key) override + { + if (key->type == SDL_KEYDOWN) { + + char c = key->keysym.sym; + + if (c == last) + ++counter; + else { + last = c; + counter = 0; + cout << "KeyCaller: Counter set to 0" << endl; + } + } + + if (counter == 20) + { + FlatSignal signal(this, "char", (void*)&last); + signal.emit("alpha"); + + cout << "KeyCaller: 20 times reached" << endl; + cout << "KeyCaller: sending " << last << endl; + } + + if (counter == 50) + { + cout << "KeyCaller: 50 times pressed " << last << endl; + + /* Exit application */ + FlatSignal signal(this, "quit"); + signal.emit("core"); + } + }; + +public: + + KeyCaller() : counter(0), last('\0') + { + setID("CALLER"); + } +}; + +class TwentyListener : public FlatListener +{ + virtual void callback(FlatObject *sender, void *data) override + { + char c = *(char*)data; + cout << "TwentyListener: received " << c << " from " << sender->getID() << endl; + } + +public: + + TwentyListener() : FlatListener({"char"}) {} +}; + +KeyPrinter printer; +KeyCaller caller; +TwentyListener twlistener; + +SignalChannel alpha("alpha"); + +int main() +{ + FlatWindow win(600, 900, "Test 3"); + flat_status status; + + /* Connect listener to alpha channel */ + alpha.connect(&twlistener); + + init_flatland(&win, loop, status, 60); + + return 0; +} + +void loop(float dt) +{ + ++count; + + if (count == 10000) + throw ForceQuit("10000 steps reached"); + + //cout << "Loop number: " << count << endl; +} + |