guit  0.1
 All Classes Functions Variables Typedefs Enumerations Friends
gnotifier.hpp
1 //
2 // implementation: notifiers for binding
3 // Guit GUI Toolkit
4 // Copyright © 2019/2020 Eric Lecolinet. All rights reserved.
5 // http://www.telecom-paris.fr/~elc
6 //
7 
8 #ifndef Guit_Notifier_hpp
9 #define Guit_Notifier_hpp
10 #include <gvarprop.hpp>
11 namespace guit {
12 
13 // [Impl] Base clase of Notifiers.
14 class GNotifier : public GProp {
15 public:
16  GNotifier* toNotifier() override {return this;}
17  GString stringValue() const override;
18  bool isEquivalent(const GProp&) const override {return false;}
19  virtual void* receiver() = 0;
20 
21  static GPropType& Type();
22  GPropType& type() const override {return Type();}
23 };
24 
25 
26 // [Impl] added to a sender to notify a receiver.
27 class GChangeNotifier : public GNotifier {
28 public:
29  void fire(GEvent&) override {doSet();}
30  virtual void* sender() = 0;
31  virtual GVarProp* receiverAsProp() = 0;
32  virtual void doSet() = 0;
33  virtual bool doTest() = 0;
34  bool recv_is_master_{};
35  int8_t bindtag_{}; // aka GVarProp::BindTag
36 };
37 
38 
39 template <class S, class R>
40 class GChangePropNotifier : public GChangeNotifier {
41 public:
42  GChangePropNotifier(S& sender, R& recv): sender_(sender), recv_(recv) {}
43 
44  void* sender() override {return &sender_;}
45  void* receiver() override {return &recv_;}
46  GVarProp* receiverAsProp() override {return &recv_;}
47  void onRemove(Gadget*) override {recv_.removeNotifiers(&sender_);}
48 
49  void doSet() override {
50  if (recv_.changing()) return; // avoids oo loops because of cross refs
51  recv_.changing(1);
52  typename R::ValueType newval{};
53  gconvert(sender_.value(), newval);
54  //recv_.set(newval,false); //wrong: calls propagateChange instead of fireCallbacks!
55  if (recv_.doChange(newval)) recv_.fireDefaultCallbacks();
56  recv_.changing(0);
57  }
58 
59  bool doTest() override {
60  typename R::ValueType newval{};
61  return gconvert(sender_.value(), newval) && recv_.isValid(newval);
62  }
63 
64  S& sender_;
65  R& recv_;
66 };
67 
68 
69 template <class S, class SF, class R, class RF>
70 class GChangeFieldNotifier : public GChangeNotifier {
71 public:
72  GChangeFieldNotifier(GPropField<S,SF> const& sender, GPropField<R,RF> const& recv):
73  sender_(sender), recv_(recv) {}
74 
75  void* sender() override {return &sender_;}
76  void* receiver() override {return &(recv_.prop_);}
77  GVarProp* receiverAsProp() override {return &(recv_.prop_);;}
78  void onRemove(Gadget*) override {recv_.prop_.removeNotifiers(&(sender_.prop_));}
79 
80  void doSet() override {
81  if (recv_.prop_.changing()) return; // avoids oo loops because of crossrefs
82  recv_.prop_.changing(1);
83  auto oldfield = recv_.field_;
84  gconvert(sender_.field_, recv_.field_);
85  auto newval = recv_.prop_.value();
86  recv_.field_ = oldfield;
87  if (recv_.prop_.doChange(newval)) recv_.prop_.fireDefaultCallbacks();
88  recv_.prop_.changing(0);
89  }
90 
91  bool doTest() override{
92  auto oldfield = recv_.field_;
93  if (!gconvert(sender_.field_, recv_.field_)) {
94  recv_.field_ = oldfield;
95  return false;
96  }
97  auto newval = recv_.prop_.value();
98  recv_.field_ = oldfield;
99  return recv_.prop_.isValid(newval);
100  }
101 
102  GPropField<S,SF> sender_;
103  GPropField<R,RF> recv_;
104 };
105 
106 
107 class GExprNotifier : public GNotifier {
108 public:
109  GExprNotifier(class GExprWrapper& wrap) : wrap(wrap) {}
110  void* receiver() override {return &wrap;}
111  void fire(GEvent&) override;
112  class GExprWrapper& wrap;
113 };
114 
115 
116 class GTriggerNotifier : public GNotifier {
117 public:
118  GTriggerNotifier(GObject& sender, class GExprTrigger& receiver);
119  void* receiver() override {return &recv_;}
120  class GExprTrigger& trigger() {return recv_;}
121  void fire(GEvent& e) override;
122  void onRemove(Gadget* g) override;
123 
124  GObject& sender_;
125  class GExprTrigger& recv_;
126 };
127 
128 
129 class GTriggerExprNotifier : public GTriggerNotifier {
130 public:
131  GTriggerExprNotifier(GObject& sender, GExprTrigger& receiver, GBoolExpr& expr);
132  void fire(GEvent&) override;
133  GBoolExpr& expr_;
134 };
135 
136 }
137 #endif