src/view.cpp in reflexion-0.1.38 vs src/view.cpp in reflexion-0.1.39

- old
+ new

@@ -1,8 +1,9 @@ #include "view.h" +#include <limits.h> #include <assert.h> #include <memory> #include <algorithm> #include <rays/matrix.h> #include "reflex/timer.h" @@ -45,34 +46,39 @@ UPDATE_SHAPES = Xot::bit(4, FLAG_LAST), UPDATE_LAYOUT = Xot::bit(5, FLAG_LAST), - FIT_TO_CONTENT = Xot::bit(6, FLAG_LAST), + SORT_CHILDREN = Xot::bit(6, FLAG_LAST), - HAS_VARIABLE_LENGTHS = Xot::bit(7, FLAG_LAST), + FIT_TO_CONTENT = Xot::bit(7, FLAG_LAST), - NO_SHAPE = Xot::bit(8, FLAG_LAST), + HAS_VARIABLE_LENGTHS = Xot::bit(8, FLAG_LAST), + NO_SHAPE = Xot::bit(9, FLAG_LAST), + };// Flag - Window* window = NULL; + Window* window = NULL; - View* parent = NULL; + View* parent = NULL; Bounds frame; - float zoom = 1; + float zoom = 1; - float angle = 0; + float angle = 0; - ushort capture = CAPTURE_NONE; + ushort capture = CAPTURE_NONE; - short hide_count = 0; + short hide_count = 0; - uint flags = FLAG_CLIP | FLAG_RESIZE_TO_FIT | REDRAW | UPDATE_LAYOUT | UPDATE_STYLE; + ushort child_index = 0; + uint flags = + FLAG_CLIP | FLAG_RESIZE_TO_FIT | REDRAW | UPDATE_LAYOUT | UPDATE_STYLE; + std::unique_ptr<Point> ppivot; std::unique_ptr<Point> pscroll; SelectorPtr pselector; @@ -97,10 +103,12 @@ std::unique_ptr<World> pchild_world; std::unique_ptr<ChildList> pchildren; + std::unique_ptr<ChildList> pchildren_sorted; + Point& pivot () { if (!ppivot) ppivot.reset(new Point); return *ppivot; } @@ -241,13 +249,14 @@ void get_body2view_matrix (Matrix* m) { assert(m && *m == 1 && ppivot && *ppivot != 0 && pbody); + Point pos = pbody->position(); Point pivot = *ppivot * frame.size(); float angle = pbody->angle(); - m->translate(pbody->position()) + m->translate(pos.x, pos.y, frame.z) .rotate(angle) .translate( pivot) .rotate(-angle) .translate(-pivot); } @@ -302,16 +311,30 @@ for (auto& wall : view->find_children(WALL_NAME)) view->remove_child(wall.get()); } - ChildList& children () + ChildList* children (bool create = false, bool sort = false) { - if (!pchildren) pchildren.reset(new ChildList); - return *pchildren; + if (!pchildren) + { + if (!create) return NULL; + pchildren.reset(new ChildList); + } + + if (sort && check_and_remove_flag(SORT_CHILDREN)) + do_sort_children(); + + return sort && pchildren_sorted ? pchildren_sorted.get() : pchildren.get(); } + void sort_children (bool order_only = false) + { + add_flag(SORT_CHILDREN); + if (!order_only && pchildren_sorted) pchildren_sorted.reset(); + } + void add_flag (uint flag) { Xot::add_flag(&flags, flag); } @@ -328,10 +351,54 @@ bool check_and_remove_flag (uint flag) { return Xot::check_and_remove_flag(&flags, flag); } + private: + + void do_sort_children () + { + assert(pchildren); + + auto& children = *pchildren; + + size_t size = children.size(); + if (size >= USHRT_MAX) + invalid_state_error(__FILE__, __LINE__, "too many children"); + + ushort index = 0; + bool have_z = false; + for (auto& child : children) + { + child->self->child_index = index++; + have_z |= child->frame().z != 0; + } + + if (!have_z) + { + pchildren_sorted.reset(); + return; + } + + if (!pchildren_sorted) + { + pchildren_sorted.reset( + new ChildList(children.begin(), children.end())); + } + + std::sort( + pchildren_sorted->begin(), pchildren_sorted->end(), + [](const auto& a, const auto& b) + { + auto *aa = a->self.get(), *bb = b->self.get(); + if (aa->frame.z != bb->frame.z) + return aa->frame.z < bb->frame.z; + else + return aa->child_index < bb->child_index; + }); + } + };// View::Data class LayoutContext { @@ -349,22 +416,22 @@ get_flow_sign(&flow_sub_h, &flow_sub_v, flow_sub); } void place_children () { - View::ChildList* pchildren = parent->self->pchildren.get(); - if (!pchildren || pchildren->empty()) + View::ChildList* children = parent->self->children(); + if (!children || children->empty()) return; bool leftward = flow_main_h < 0 || flow_sub_h < 0; bool upward = flow_main_v < 0 || flow_sub_v < 0; Point start_position( leftward ? parent_frame.width : 0, upward ? parent_frame.height : 0); Point position = start_position; - for (iterator begin = pchildren->begin(), end = pchildren->end(); true;) + for (iterator begin = children->begin(), end = children->end(); true;) { iterator line_end; coord main_fill_size = 0; coord sub_size_max = 0; calc_line(&line_end, &main_fill_size, &sub_size_max, begin, end); @@ -651,15 +718,15 @@ } view->self->window = window; view->self->update_body_and_shapes(); - View::ChildList* pchildren = view->self->pchildren.get(); - if (pchildren) + View::ChildList* children = view->self->children(); + if (children) { - for (auto& pchild : *pchildren) - View_set_window(pchild.get(), window); + for (auto& child : *children) + View_set_window(child.get(), window); } if (view->self->window) { Event e; @@ -671,19 +738,19 @@ static void apply_style_to_children_have_variable_lengths (View* parent) { assert(parent); - View::ChildList* pchildren = parent->self->pchildren.get(); - if (!pchildren) return; + View::ChildList* children = parent->self->children(); + if (!children) return; - for (auto& pchild : *pchildren) + for (auto& child : *children) { - assert(pchild); + assert(child); - if (pchild->self->has_flag(View::Data::HAS_VARIABLE_LENGTHS)) - pchild->self->add_flag(View::Data::APPLY_STYLE); + if (child->self->has_flag(View::Data::HAS_VARIABLE_LENGTHS)) + child->self->add_flag(View::Data::APPLY_STYLE); } } static void update_view_layout (View* view, bool update_parent = false) @@ -731,10 +798,13 @@ } if (update_body && (moved || rotated) && self->pbody) self->update_body_frame(); + if (moved && event.dz() != 0 && self->parent) + self->parent->self->sort_children(true); + if ((moved || resized) && self->parent) self->parent->self->add_flag(View::Data::FIT_TO_CONTENT); view->redraw(); } @@ -777,23 +847,23 @@ View::ChildList* result, const View* view, const Selector& selector, bool recursive) { assert(result && view); - View::ChildList* pchildren = view->self->pchildren.get(); - if (!pchildren) return; + View::ChildList* children = view->self->children(); + if (!children) return; - for (auto& pchild : *pchildren) + for (auto& child : *children) { - if (!pchild) + if (!child) invalid_state_error(__FILE__, __LINE__); - if (pchild->selector().contains(selector)) - result->push_back(pchild); + if (child->selector().contains(selector)) + result->push_back(child); if (recursive) - find_all_children(result, pchild.get(), selector, true); + find_all_children(result, child.get(), selector, true); } } static void find_all_styles ( @@ -812,15 +882,15 @@ } } if (!recursive) return; - View::ChildList* pchildren = view->self->pchildren.get(); - if (pchildren) + View::ChildList* children = view->self->children(); + if (children) { - for (auto& pchild : *pchildren) - find_all_styles(result, pchild.get(), selector, true); + for (auto& child : *children) + find_all_styles(result, child.get(), selector, true); } } static void fire_timers (View* view, double now) @@ -864,11 +934,14 @@ Matrix m; self->get_body2view_matrix(&m); frame.set_position(m * Point(0)); } else - frame.set_position(body->position()); + { + Point pos = body->position(); + frame.set_position(pos.x, pos.y, frame.z); + } update_view_frame(view, frame, view->zoom(), body->angle(), false); } static void @@ -880,15 +953,15 @@ World* child_world = self->pchild_world.get(); if (!child_world) return; child_world->on_update(dt); - View::ChildList* pchildren = self->pchildren.get(); - if (pchildren) + View::ChildList* children = self->children(); + if (children) { - for (auto& pchild : *pchildren) - update_view_body(pchild.get()); + for (auto& child : *children) + update_view_body(child.get()); } } static void update_views_for_selectors (View* view) @@ -908,12 +981,12 @@ if (view_sel && view_sel->contains(sel)) self->add_flag(View::Data::UPDATE_STYLE); children.clear(); find_all_children(&children, view, sel, true); - for (auto& pchild : children) - pchild->self->add_flag(View::Data::UPDATE_STYLE); + for (auto& child : children) + child->self->add_flag(View::Data::UPDATE_STYLE); } sels->clear(); } @@ -1008,15 +1081,15 @@ View::Data* self = view->self.get(); fire_timers(view, event.now()); - View::ChildList* pchildren = self->pchildren.get(); - if (pchildren) + View::ChildList* children = self->children(); + if (children) { - for (auto& pchild : *pchildren) - View_update_tree(pchild.get(), event); + for (auto& child : *children) + View_update_tree(child.get(), event); } update_view_shapes(view); update_child_world(view, event.dt()); @@ -1146,17 +1219,17 @@ p->pop_state(); if (event->is_blocked()) return; - View::ChildList* pchildren = self->pchildren.get(); - if (pchildren) + View::ChildList* children = self->children(false, true); + if (children) { - for (auto& pchild : *pchildren) + for (auto& child : *children) { - if (event->bounds() & pchild->self->frame) - View_draw_tree(pchild.get(), event, offset, clip); + if (event->bounds() & child->self->frame) + View_draw_tree(child.get(), event, offset, clip); } } World* child_world = self->pchild_world.get(); if (child_world) @@ -1319,19 +1392,18 @@ default: break; } } static void - call_children (View* parent, std::function<bool(View*)> fun) + call_children (View* parent, std::function<bool(View*)> fun, bool sort = true) { assert(parent); - auto* pchildren = parent->self->pchildren.get(); - if (!pchildren) return; + auto* children = parent->self->children(false, sort); + if (!children) return; - auto end = pchildren->rend(); - for (auto it = pchildren->rbegin(); it != end; ++it) + for (auto it = children->rbegin(), end = children->rend(); it != end; ++it) { if (!fun(it->get())) break; } } @@ -1365,10 +1437,13 @@ case Pointer::UP: view->on_pointer_up(event); break; case Pointer::MOVE: view->on_pointer_move(event); break; case Pointer::CANCEL: view->on_pointer_cancel(event); break; default: break; } + + if (!event->is_captured()) + PointerEvent_increment_view_indices(event); } static void register_captures (View* view, const PointerEvent& event) { @@ -1379,11 +1454,11 @@ invalid_state_error(__FILE__, __LINE__); PointerEvent_each_pointer(&event, [&](const auto& pointer) { if (pointer.action() == Pointer::DOWN) - Window_register_capture(win, view, pointer.id()); + Window_register_capture(win, view, pointer.id(), pointer.view_index()); }); } static void unregister_captures (View* view, const PointerEvent& event) @@ -1708,20 +1783,23 @@ static void erase_child_from_children (View* parent, View* child) { assert(parent && child); - View::ChildList* children = parent->self->pchildren.get(); + View::ChildList* children = parent->self->children(); if (!children) return; auto end = children->end(); auto it = std::find(children->begin(), end, child); assert(it != end); children->erase(it); if (children->empty()) + { parent->self->pchildren.reset(); + parent->self->pchildren_sorted.reset(); + } } void View::add_child (View* child) { @@ -1733,18 +1811,20 @@ if (found && belong) return; else if (found != belong) invalid_state_error(__FILE__, __LINE__); - self->children().push_back(child); + self->children(true)->push_back(child); View* prev_parent = child->parent(); set_parent(child, this); if (prev_parent) erase_child_from_children(prev_parent, child); + self->sort_children(); + update_view_layout(this); } void View::remove_child (View* child) @@ -1761,20 +1841,22 @@ set_parent(child, NULL); erase_child_from_children(this, child); + self->sort_children(); + update_view_layout(this); } void View::clear_children () { - if (!self->pchildren || self->pchildren->empty()) return; + auto* children = self->children(); + if (!children || children->empty()) return; - auto children = *self->pchildren; - for (auto& child : children) + for (auto& child : *children) remove_child(child); } View::ChildList View::find_children (const Selector& selector, bool recursive) const @@ -2262,12 +2344,12 @@ bool registered = old != CAPTURE_NONE; bool capture = types != CAPTURE_NONE; if (capture && !registered) - Window_register_capture(w, this); + Window_register_capture(w, this, CAPTURE_ALL); else if (!capture && registered) - Window_unregister_capture(w, this); + Window_unregister_capture(w, this, CAPTURE_ALL); CaptureEvent e(~old & types, old & ~types); on_capture(&e); }