Empirical
Div.h
Go to the documentation of this file.
1 
29 #ifndef EMP_WEB_DIV_H
30 #define EMP_WEB_DIV_H
31 
32 
33 #include "Animate.h"
34 #include "Text.h"
35 #include "Widget.h"
36 
37 #include "init.h"
38 
39 namespace emp {
40 namespace web {
41 
42  class Button;
43  class Canvas;
44  class Image;
45  class Selector;
46  class Div;
47  class Table;
48 
49  namespace internal {
50 
51  class TableInfo;
52  class DivInfo : public internal::WidgetInfo {
53  friend Div; friend TableInfo;
54  protected:
55  double scroll_top;
57  bool append_ok;
58  bool text_append;
59  std::map<std::string, Widget> widget_dict;
60  std::map<std::string, web::Animate *> anim_map;
61 
62  DivInfo(const std::string & in_id="")
63  : internal::WidgetInfo(in_id), scroll_top(0.0), append_ok(true), text_append(false)
64  , widget_dict(), anim_map()
65  {
67  }
68  DivInfo(const DivInfo &) = delete; // No copies of INFO allowed
69  DivInfo & operator=(const DivInfo &) = delete; // No copies of INFO allowed
70  virtual ~DivInfo() {
71  for (auto & p : anim_map) delete p.second; // Delete this document's animations.
72  }
73 
74  std::string TypeName() const override { return "DivInfo"; }
75 
76  virtual bool IsDivInfo() const override { return true; }
77 
78 
79  bool IsRegistered(const std::string & test_name) const {
80  return (widget_dict.find(test_name) != widget_dict.end());
81  }
82 
83  Widget & GetRegistered(const std::string & find_name) {
84  emp_assert(IsRegistered(find_name), find_name, widget_dict.size());
85  return widget_dict[find_name];
86  }
87 
88  void Register_recurse(Widget & new_widget) override {
89  emp_assert(IsRegistered(new_widget.GetID()) == false, new_widget.GetID());
90  widget_dict[new_widget.GetID()] = new_widget; // Track widget by name
91  if (parent) parent->Register_recurse(new_widget); // Also register in parent, if available
92  }
93 
94  // Register is used so we can lookup classes by name.
95  void Register(Widget & new_widget) override {
96  Register_recurse(new_widget); // Register THIS widget here an in ancestors.
97  new_widget->RegisterChildren( this ); // Register CHILD widgets, if any
98  }
99 
100  void RegisterChildren(DivInfo * regestrar) override {
101  for (Widget & child : m_children) regestrar->Register(child);
102  }
103 
104  void Unregister_recurse(Widget & old_widget) override {
105  emp_assert(IsRegistered(old_widget.GetID()) == true, old_widget.GetID());
106  widget_dict.erase(old_widget.GetID());
107  if (parent) parent->Unregister_recurse(old_widget); // Unregister in parent, if available
108  }
109 
110  void Unregister(Widget & old_widget) override {
111  Unregister_recurse(old_widget); // Unregister this node from all above.
112  old_widget->UnregisterChildren( this ); // Unregister all children, if any.
113  old_widget->parent = nullptr;
114  old_widget.Deactivate(false);
115  }
116 
117  void UnregisterChildren(DivInfo * regestrar) override {
118  for (Widget & child : m_children) regestrar->Unregister(child);
119  }
120 
121  void ClearChildren() {
122  // Unregister all children and then delete links to them.
123  for (Widget & child : m_children) Unregister(child);
124  m_children.resize(0);
125  if (state == Widget::ACTIVE) ReplaceHTML();
126  }
127 
128  void Clear() {
129  ClearChildren();
130  extras.Clear();
131  if (state == Widget::ACTIVE) ReplaceHTML();
132  }
133 
134  void AddChild(Widget in) {
135  // If the inserted widget is already active, remove it from its old position.
136  emp_assert(in->parent == nullptr && "Cannot insert widget if already has parent!", in->id);
137  emp_assert(in->state != Widget::ACTIVE && "Cannot insert a stand-alone active widget!");
138 
139  // Setup parent-child relationship
140  m_children.emplace_back(in);
141  in->parent = this;
142  Register(in);
143 
144  // If this element (as new parent) is active, anchor widget and activate it!
145  if (state == Widget::ACTIVE) {
146  // Create a span tag to anchor the new widget.
147  EM_ASM_ARGS({
148  parent_id = Pointer_stringify($0);
149  child_id = Pointer_stringify($1);
150  $('#' + parent_id).append('<span id="' + child_id + '"></span>');
151  }, id.c_str(), in.GetID().c_str());
152 
153  // Now that the new widget has some place to hook in, activate it!
154  in->DoActivate();
155  }
156  }
157 
158  void DoActivate(bool top_level=true) override {
159  for (auto & child : m_children) child->DoActivate(false);
161  }
162 
163 
164  // Return a text element for appending. Use the last element unless there are no elements,
165  // the last element is not text, or it is not appendable (instead, build a new one).
167  // If the final element is not appendable text, add a new Text widget.
168  if (m_children.size() == 0
169  || m_children.back().IsText() == false
170  || m_children.back().AppendOK() == false
171  || text_append == false) {
172  AddChild(Text());
173  text_append = true;
174  }
175  return (Text &) m_children.back();
176  }
177 
178  bool AppendOK() const override { return append_ok; }
179  void PreventAppend() override { append_ok = false; }
180 
181  // Add additional children on to this element.
182  Widget Append(const std::string & text) override {
183  if (!append_ok) return ForwardAppend(text);
184  return GetTextWidget() << text;
185  }
186  Widget Append(const std::function<std::string()> & in_fun) override {
187  if (!append_ok) return ForwardAppend(in_fun);
188  return GetTextWidget() << in_fun;
189  }
190 
191  Widget Append(Widget info) override {
192  if (!append_ok) return ForwardAppend(info);
193  AddChild(info);
194  text_append = false; // A widget is being passed in, so don't all text appends.
195  return info;
196  }
197 
199  Widget Append(const Font & font) override {
200  if (!append_ok) return ForwardAppend(font);
201  Text new_text; // Build a new text widget for this font.
202  new_text.SetFont(font); // Setup the new text widget with the provided font.
203  AddChild(new_text); // Add this new text widget to this div.
204  text_append = true; // Since we added a Text widget with this font, it can be extended.
205  return new_text;
206  }
207 
208  // All derived widgets must suply a mechanism for providing associated HTML code.
209  virtual void GetHTML(std::stringstream & HTML) override {
210  HTML.str(""); // Clear the current text.
211 
212  // Loop through all children and build a span element for each to replace.
213  HTML << "<div id=\'" << id << "\'>"; // Tag to envelope Div
214  for (Widget & w : m_children) {
215  HTML << "<span id=\'" << w.GetID() << "'></span>"; // Span element for current widget.
216  }
217  HTML << "</div>";
218  }
219 
220 
221  void ReplaceHTML() override {
222  // Replace Div's HTML...
224 
225  // Then replace children.
226  if (state == Widget::ACTIVE) {
227  for (auto & child : m_children) child->ReplaceHTML();
228  }
229 
230  if (scroll_top >= 0.0) {
231  EM_ASM_ARGS({
232  var div_id = Pointer_stringify($0);
233  var div_obj = document.getElementById(div_id);
234  if (div_obj == null) alert(div_id);
235  // alert('id=' + div_id + ' top=' + $1 +
236  // ' height=' + div_obj.scrollHeight);
237  var scroll_top = $1 * div_obj.scrollHeight;
238  div_obj.scrollTop = scroll_top;
239  }, id.c_str(), scroll_top);
240  }
241 
242  // @CAO If scrolltop is set, handle scrolling!
243  // float scroll_frac = ((float) (hardware->GetIP() - 3)) / (float) hardware->GetNumInsts();
244  // if (scroll_frac < 0.0) scroll_frac = 0.0;
245 
246  // EM_ASM_ARGS({
247  // var code = Pointer_stringify($0);
248  // var code_obj = document.getElementById("code");
249  // code_obj.innerHTML = code;
250  // code_obj.scrollTop = $1 * code_obj.scrollHeight;
251  // var cycle_obj = document.getElementById("cycle_count");
252  // cycle_obj.innerHTML = "&nbsp;&nbsp;&nbsp;Cycles Used = " + $2;
253  // }, ss.str().c_str(), scroll_frac, hardware->GetExeCount());
254 
255  }
256 
257  public:
258  virtual std::string GetType() override { return "web::DivInfo"; }
259  };
260  }
261 
263  class Div : public internal::WidgetFacet<Div> {
264  protected:
265  // Get a properly cast version of indo.
266  internal::DivInfo * Info() { return (internal::DivInfo *) info; }
267  const internal::DivInfo * Info() const { return (internal::DivInfo *) info; }
268 
269  public:
270  Div(const std::string & in_name) : WidgetFacet(in_name) {
271  // When a name is provided, create an associated Widget info.
272  info = new internal::DivInfo(in_name);
273  }
274  Div(const Div & in) : WidgetFacet(in) { ; }
275  Div(const Widget & in) : WidgetFacet(in) { emp_assert(info->IsDivInfo()); }
276  Div() { ; }
277  ~Div() { ; }
278 
280 
282  double ScrollTop() const { return Info()->scroll_top; }
283 
285  Div & ScrollTop(double in_top) { Info()->scroll_top = in_top; return *this; }
286 
288  void Clear() { if (info) Info()->Clear(); }
289 
291  void ClearChildren() { if (info) Info()->ClearChildren(); }
292 
294  bool HasChild(const Widget & test_child) const {
295  if (!info) return false;
296  for (const Widget & c : Info()->m_children) if (c == test_child) return true;
297  return false;
298  }
299 
301  void Deactivate(bool top_level) override {
302  // Deactivate children before this node.
303  for (auto & child : Info()->m_children) child.Deactivate(false);
304  Widget::Deactivate(top_level);
305  }
306 
308  Widget & Find(const std::string & test_name) {
309  emp_assert(info);
310  return Info()->GetRegistered(test_name);
311  }
312 
314  emp::vector<Widget> & Children() { return Info()->m_children; }
315 
317  template <class... T> web::Animate & AddAnimation(const std::string & name, T &&... args){
318  web::Animate * new_anim = new web::Animate(std::forward<T>(args)...);
319  emp_assert(Info()->anim_map.find(name) == Info()->anim_map.end()); // Make sure not in map already!
320  Info()->anim_map[name] = new_anim;
321  return *new_anim;
322  }
323 
324  // A quick way to retrieve Animate widgets by name.
325  web::Animate & Animate (const std::string & in_id) { return *(Info()->anim_map[in_id]); }
326  };
327 
328  // using Slate = Div; // For backward compatability...
329 }
330 }
331 
332 #endif
A Text widget handles putting text on a web page that can be controlled and modified.
Definition: Text.h:27
void ClearChildren()
Remove all child widgets from this div.
Definition: Div.h:291
Definition: Widget.h:206
void ReplaceHTML() override
Definition: Div.h:221
DivInfo(const std::string &in_id="")
Definition: Div.h:62
~Div()
Definition: Div.h:277
void UnregisterChildren(DivInfo *regestrar) override
Definition: Div.h:117
virtual void ReplaceHTML()
Definition: Widget.h:319
Define Initialize() and other functions to set up Empirical to build Emscripten projects.
std::string id
ID used for associated DOM element.
Definition: Widget.h:212
void ClearChildren()
Definition: Div.h:121
void Unregister(Widget &old_widget) override
Definition: Div.h:110
emp::vector< Widget > m_children
Widgets contained in this one.
Definition: Div.h:56
WidgetFacet is a template that provides accessors into Widget with a derived return type...
Definition: Widget.h:543
Widget & GetRegistered(const std::string &find_name)
Definition: Div.h:83
std::map< std::string, web::Animate * > anim_map
Streamline creation of Animate objects.
Definition: Div.h:60
bool text_append
Can we append to a current text widget?
Definition: Div.h:58
Include information (name, keyword, description) for each instance.
Manage animations on a web site.
Widget Append(const std::function< std::string()> &in_fun) override
Definition: Div.h:186
Specs for the Text widget.
emp::vector< Widget > & Children()
Get all direct child widgets to this div.
Definition: Div.h:314
Div(const Widget &in)
Definition: Div.h:275
Div(const Div &in)
Definition: Div.h:274
internal::DivInfo * Info()
Definition: Div.h:266
virtual void Unregister_recurse(Widget &w)
Definition: Widget.h:253
An object that, when active, repeatedly calls a function as fast as possible, to a maximum of 60 fram...
Definition: Animate.h:62
Definition: Widget.h:102
double ScrollTop() const
Where is the top of the scroll region?
Definition: Div.h:282
Div()
Definition: Div.h:276
Div & ScrollTop(double in_top)
Set the scroll position.
Definition: Div.h:285
bool AppendOK() const override
Definition: Div.h:178
static bool Initialize()
Stub for when Emscripten is not in use.
Definition: init.h:98
double scroll_top
Where should div scroll to? (0.0 to 1.0)
Definition: Div.h:55
size_t size() const
Definition: vector.h:151
WidgetExtras extras
HTML attributes, CSS style, and listeners for web events.
Definition: Widget.h:213
void emplace_back(ARGS &&...args)
Definition: vector.h:219
void PreventAppend() override
Definition: Div.h:179
web::Text & GetTextWidget()
Definition: Div.h:166
virtual void RegisterChildren(DivInfo *registrar)
Definition: Widget.h:257
Widget::ActivityState state
Is this element active in DOM?
Definition: Widget.h:218
Widget Append(const std::string &text) override
Definition: Div.h:182
void Clear()
Clear all of style, attributes, and listeners.
Definition: WidgetExtras.h:46
virtual bool IsDivInfo() const override
Definition: Div.h:76
const std::string & GetID() const
What is the HTML string ID for this Widget?
Definition: Widget.h:401
Widget Append(Widget info) override
Definition: Div.h:191
Div(const std::string &in_name)
Definition: Div.h:270
virtual void GetHTML(std::stringstream &HTML) override
Definition: Div.h:209
A widget to track a div in an HTML file, and all of its contents.
Definition: Div.h:263
WidgetInfo * parent
Which WidgetInfo is this one contained within?
Definition: Widget.h:216
const internal::DivInfo * Info() const
Definition: Div.h:267
std::string TypeName() const override
Debugging helpers...
Definition: Div.h:74
Definition: Div.h:52
virtual std::string GetType() override
Definition: Div.h:258
virtual ~DivInfo()
Definition: Div.h:70
Widget & Find(const std::string &test_name)
Get an internal widget to this div, by the specified name.
Definition: Div.h:308
bool IsRegistered(const std::string &test_name) const
Definition: Div.h:79
Widget Append(const Font &font) override
Start a new set of Text with this font (even if one already exists.)
Definition: Div.h:199
void DoActivate(bool top_level=true) override
Definition: Div.h:158
return_t & SetFont(const Font &font)
Provide a Font object to setup the font for this widget.
Definition: Widget.h:798
web::Animate & AddAnimation(const std::string &name, T &&...args)
Shortcut adder for animations.
Definition: Div.h:317
Widgets maintain individual components on a web page and link to Elements.
bool append_ok
Can we add more children?
Definition: Div.h:57
void Unregister_recurse(Widget &old_widget) override
Definition: Div.h:104
If we are in emscripten, make sure to include the header.
Definition: array.h:37
Widget ForwardAppend(FWD_TYPE &&arg)
Definition: Widget.h:307
std::map< std::string, Widget > widget_dict
By-name lookup for descendent widgets.
Definition: Div.h:59
virtual void DoActivate(bool top_level=true)
Definition: Widget.h:278
Build a debug wrapper emp::vector around std::vector.
Definition: vector.h:42
virtual void Register_recurse(Widget &w)
Definition: Widget.h:251
Widget is effectively a smart pointer to a WidgetInfo object, plus some basic accessors.
Definition: Widget.h:78
DivInfo & operator=(const DivInfo &)=delete
#define emp_assert(...)
Definition: assert.h:199
T & back()
Definition: vector.h:183
void Deactivate(bool top_level) override
Remove this widget from the current document.
Definition: Div.h:301
void AddChild(Widget in)
Definition: Div.h:134
virtual void UnregisterChildren(DivInfo *regestrar)
Definition: Widget.h:258
void Register(Widget &new_widget) override
Definition: Div.h:95
void Register_recurse(Widget &new_widget) override
Definition: Div.h:88
Definition: Table.h:107
void RegisterChildren(DivInfo *regestrar) override
Definition: Div.h:100
Maintain information about an HTML font.
Definition: Font.h:24
web::Animate & Animate(const std::string &in_id)
Definition: Div.h:325
void Clear()
Definition: Div.h:128
void Clear()
Clear the contents of this div.
Definition: Div.h:288
bool HasChild(const Widget &test_child) const
Determine if a specified widget is internal to this one.
Definition: Div.h:294
virtual void Deactivate(bool top_level=true)
Definition: Widget.h:504