src/view.cpp in reflexion-0.1.6 vs src/view.cpp in reflexion-0.1.7

- old
+ new

@@ -1,277 +1,1207 @@ #include "reflex/view.h" -#include <string.h> +#include <assert.h> +#include <algorithm> +#include <boost/scoped_ptr.hpp> #include <rays/bounds.h> #include <rays/painter.h> -#include <reflex/window.h> +#include "reflex/window.h" +#include "reflex/exception.h" namespace Reflex { - typedef std::vector<View::Ref> ViewList; + void set_focus (Window* window, View* view); - static ViewList empty_list; + void register_capture (View* view); + void unregister_capture (View* view); + struct View::Data { - typedef ViewList:: iterator iterator; + Window* window; - typedef ViewList::const_iterator const_iterator; + View* parent; - String name; + Bounds frame; - Bounds bounds; + boost::scoped_ptr<Selector> pselector; - int hidecount; + boost::scoped_ptr<Point> pscroll; - View* parent; + boost::scoped_ptr<ChildList> pchildren; - Window* window; + boost::scoped_ptr<StyleList> pstyles; - ViewList* pchildren_; + Style style; + ushort capture; + + short hide_count; + + uint flags; + Data () - : hidecount(0), parent(NULL), pchildren_(NULL) + : window(NULL), parent(NULL), + capture(CAPTURE_NONE), hide_count(0), flags(0) { } ~Data () { - delete pchildren_; } - bool set_parent (View* parent_) + Selector& selector () { - if (parent_ && parent) return false; + if (!pselector) pselector.reset(new Selector); + return *pselector; + } - parent = parent_; - window = parent_ ? parent_->window() : NULL; - return true; + Point& scroll () + { + if (!pscroll) pscroll.reset(new Point); + return *pscroll; } - ViewList* children () + ChildList& children () { - if (pchildren_ == NULL) pchildren_ = new ViewList(); - return pchildren_; + if (!pchildren) pchildren.reset(new ChildList); + return *pchildren; } - iterator begin () + StyleList& styles () { - if (!pchildren_) return empty_list.begin(); - return pchildren_->begin(); + if (!pstyles) pstyles.reset(new StyleList); + return *pstyles; } - const_iterator begin () const + };// View::Data + + + void + set_window (View* this_, Window* window_) + { + if (!this_) + argument_error(__FILE__, __LINE__); + + Window* current = this_->self->window; + if (current == window_) return; + + if (current) { - if (!pchildren_) return empty_list.begin(); - return pchildren_->begin(); + this_->set_capture(View::CAPTURE_NONE); + + Event e; + this_->on_detach(&e); } - iterator end () + this_->self->window = window_; + + View::child_iterator end = this_->child_end(); + for (View::child_iterator it = this_->child_begin(); it != end; ++it) + set_window(it->get(), window_); + + if (this_->self->window) { - if (!pchildren_) return empty_list.end(); - return pchildren_->end(); + Event e; + this_->on_attach(&e); } + } - const_iterator end () const + static void + set_parent (View* this_, View* parent_) + { + if (!this_) + argument_error(__FILE__, __LINE__); + + View* current = this_->self->parent; + if (current == parent_) return; + + if (current && parent_) { - if (!pchildren_) return empty_list.end(); - return pchildren_->end(); + reflex_error(__FILE__, __LINE__, + "view '%s' already belongs to another parent '%s'.", + this_->name(), this_->self->parent->name()); + } + this_->self->parent = parent_; + set_window(this_, parent_ ? parent_->window() : NULL); + } + + void + update_view_tree (View* view, const UpdateEvent& event) + { + if (!view) + argument_error(__FILE__, __LINE__); + + UpdateEvent e = event; + view->on_update(&e); + + View::child_iterator end = view->child_end(); + for (View::child_iterator it = view->child_begin(); it != end; ++it) + update_view_tree(it->get(), e); + } + + void + draw_view_tree ( + View* view, const DrawEvent& event, const Point& offset, const Bounds& clip) + { + if (!view) + argument_error(__FILE__, __LINE__); + + DrawEvent e = event; + e.painter->push_matrix(); + e.painter->push_attr(); + + Bounds b = view->frame(); + Point p = b.position() - view->scroll(); + e.painter->translate(p); + + p += offset; + Bounds c = clip & b.move_to(p); + e.painter->set_clip(c); + + e.view = view; + e.bounds = b.move_to(0, 0, b.z); + view->on_draw(&e); + + View::child_iterator end = view->child_end(); + for (View::child_iterator it = view->child_begin(); it != end; ++it) + draw_view_tree(it->get(), e, p, c); + + e.painter->pop_attr(); + e.painter->pop_matrix(); + } +#if 0 + void + get_all_margins (MarginList* margins, View* view) + { + if (!margins || !view) + argument_error(__FILE__, __LINE__); + } + + void + get_content_size ( + Point* size, View* view, const Point& parent_size, bool min_width, bool min_height) + { + if (!size || !view) + argument_error(__FILE__, __LINE__); + + const Style& style = view->style(); + const StyleLength4& pos = style.position(); + const StyleLength2& size = style.size(); + const StyleLength4& margin = style.margin(); + bool need_width = true, need_height = true; + coord n; + + size->reset(0); + + if (pos.left && pos.right) + { + if (!pos.left.is_fixed()) + layout_error(__FILE__, __LINE__, ""); + + size->x += parent_size.x; + need_width = false; } + else if (size.width.get_pixel(&n, parent_size.x)) + { + size->x += n; + need_width = false; + } - };// View::Data + if (pos.top && pos.bottom) + size->y += parent_size.y; + else if (size.height.get_pixel(&n, parent_size.y)) + size->y += n; + else + need_height = true; + if (need_width || need_height) + { + Point content_size = view->content_size(); + bool view_width = false, view_height = false; + if (need_width && content_size.x >= 0) + { + size->x += content_size.x; + need_width = false; + } + + if (need_height && content_size.y >= 0) + { + size->y += content_size.y; + need_height = false; + } + + if (need_width || need_height) + { + View::child_iterator end = view->child_end(); + for (View::child_iterator it = view->child_begin(); it != end; ++it) + { + const View* child = it->get(); + Point child_size; + get_content_size(&child_size, child, ); + const Bounds& b = it->frame(); + } + + for () + Point view_size; + get_view_size(&view_size, ); + } + + coord m; + if (margin.left .get_pixel(&m, parent_size.x)) size->x += m; + if (margin.top .get_pixel(&m, parent_size.y)) size->y += m; + if (margin.right .get_pixel(&m, parent_size.x)) size->x += m; + if (margin.bottom.get_pixel(&m, parent_size.y)) size->y += m; + } + + + + + + + + const StyleLength4& margin = style.margin(); + + coord left, top, right, bottom; + bool have_left = pos.left .get_pixel(&left, parent_width); + bool have_top = pos.top .get_pixel(&top, parent_height); + bool have_right = pos.right .get_pixel(&right, parent_width); + bool have_bottom = pos.bottom.get_pixel(&bottom, parent_height); + + if (have_left && have_right) + { + s + } + + coord width, height; + bool have_width = size.width .get_pixel(&width, parent_width); + bool have_height = size.height.get_pixel(&height, parent_height); + const StyleLength& w = style.width(); + switch (w.unit()) + { + case StyleLength::PIXEL: + case StyleLength::PERCENT: + case StyleLength::NONE: + default: + } + } + + static void + get_flow_factor (int* h, int* v, Style::Flow flow) + { + if (!h || !v) + argument_error(__FILE__, __LINE__); + + switch (flow) + { + case Style::FLOW_DOWN: *h = 0; *v = +1; break; + case Style::FLOW_RIGHT: *h = +1; *v = 0; break; + case Style::FLOW_UP: *h = 0; *v = -1; break; + case Style::FLOW_LEFT: *h = -1; *v = 0; break; + default: argument_error(__FILE__, __LINE__); + } + } + + struct Length4 + { + + coord l, t, r, b; + + Length4 () + { + } + + Length4 (const StyleLength4& soruce) + { + reset(source); + } + + void reset (const StyleLength4& source) + { + source.left .get_pixel(&l, 0); + source.top .get_pixel(&t, 0); + source.right .get_pixel(&r, 0); + source.bottom.get_pixel(&b, 0); + } + + };// Length4 + + struct ChildView + { + + View* view; + + Point size; + + Length4 margin; + + ChildView (View* view) : view(view) {} + + };// ChildView + + typedef std::vector<ChildView> ChildViewList; + + static void reflow_view_tree (Point* size, Length4* margin, View* view); + + static void + reflow_children (View* view, Point* size, const Style& style) + { + assert(view && size); + + size_t nchildren = view->self->count_children(); + if (nchildren == 0) return; + + ChildViewList children; + children.reserve(nchildren); + + View::child_iterator end = view->child_end(); + for (View::child_iterator it = view->child_begin(); it != end; ++it) + { + ChildView c(it->get()); + reflow_view_tree(&c.size, &c.margin, c.view); + children.push_back(c); + } + + assert(children.size() == nchildren) +#if 0 + Flow flow_main, flow_sub; + style.get_flow(&flow_main, &flow_sub); + + int main_h, main_v, sub_h, sub_v; + get_flow_factor(&main_h, &main_v, flow_main); + get_flow_factor(&sub_h, &sub_v, flow_sub); +#endif + coord x = 0, y = 0; + coord parent_w = size->x, parent_h = size->y; + coord height_max = 0; + int child_count = 0; + bool multiline = sub != Style::FLOW_NONE; + + for (size_t i = 0; i < nchildren; ++i) + { + const ChildView& child = children[i]; + Bounds& child_frame = child.view->self->frame; + + child_frame.x = x; + child_frame.y = y; + x += child.size.x; + + if (child.size.y > size_max) + size_max = child.size.y; + + if (parent_w >= 0 && x > parent_w && view_count > 0) + { + x = 0; + y += size_max; + size_max = 0; + if (parent_h < 0 && y > size->y) size->y = y; + } + + ++view_count; + } + } + + static void + reflow_view_tree (Point* size, Length4* margin, View* view) + { + if (!size || !margin || !view) + argument_error(__FILE__, __LINE__); + + const Style& style = view->style(); + + *size = view->content_size(); + reflow_children(view, size, style); + + Length4 padding(style.padding()); + size->x += padding.l + padding.r; + size->y += padding.t + padding.b; + + Bounds& frame = view->self->frame; + margin->reset(style.margin()); + + frame.width = margin.l + size->x + margin.r; + frame.height = margin.t + size->y + margin.b; + } + void - set_owner_window (View* view, Window* owner) + get_fixed_content_size (Point* size, View* view) { - if (!view) return; - view->self->window = owner; + if (!size || !view) + argument_error(__FILE__, __LINE__); + + const Style& style = view->style(); + const StyleLength2& size = style.size(); + bool need_width = true, need_height = true; + coord n; + + size->reset(-1); + + if (size.width.is_fixed() && size.width.get_pixel(&n, parent_size.x)) + { + size->x += n; + need_width = false; + } + + if (size.height.get_pixel(&n, parent_size.y)) + { + size->y += n; + need_height = false; + } + + if (need_width || need_height) + { + Point content_size = view->content_size(); + bool view_width = false, view_height = false; + + if (need_width && content_size.x >= 0) + { + size->x += content_size.x; + need_width = false; + } + + if (need_height && content_size.y >= 0) + { + size->y += content_size.y; + need_height = false; + } + + if (need_width || need_height) + { + View::child_iterator end = view->child_end(); + for (View::child_iterator it = view->child_begin(); it != end; ++it) + { + const View* child = it->get(); + Point child_size; + get_content_size(&child_size, child, ); + const Bounds& b = it->frame(); + } + + for () + Point view_size; + get_view_size(&view_size, ); + } + + coord m; + if (margin.left .get_pixel(&m, parent_size.x)) size->x += m; + if (margin.top .get_pixel(&m, parent_size.y)) size->y += m; + if (margin.right .get_pixel(&m, parent_size.x)) size->x += m; + if (margin.bottom.get_pixel(&m, parent_size.y)) size->y += m; + } } +#endif + static void + reflow_children (View* parent, const FrameEvent* event = NULL) + { + if (!parent) + argument_error(__FILE__, __LINE__); + if (!parent->self->pchildren) return; + + View::ChildList& children = *parent->self->pchildren; + if (children.empty()) return; + +#if 0 + int main_h, main_v, sub_h, sub_v; + get_flow_factor(&main_h, &main_v, flow_main); + get_flow_factor(&sub_h, &sub_v, flow_sub); +#endif + + const Style& style = parent->style(); + + Style::Flow flow_main, flow_sub; + style.get_flow(&flow_main, &flow_sub); + + const Bounds& parent_frame = parent->self->frame; + coord x = 0, y = 0, size_max = 0; + int child_count = 0; + bool multiline = flow_sub != Style::FLOW_NONE; + + size_t nchildren = children.size(); + for (size_t i = 0; i < nchildren; ++i) + { + View* child = children[i].get(); + Bounds child_frame = child->self->frame; + + if ( + (x + child_frame.width) > parent_frame.width && + child_count > 0)// && multiline) + { + x = 0; + y += size_max; + size_max = 0; + child_count = 0; + } + + child_frame.x = x; + child_frame.y = y; + + x += child_frame.width; + + if (size_max < child_frame.height) + size_max = child_frame.height; + + //if (y + size_max > parent_frame.height) + // parent_frame.height = y + size_max; + + ++child_count; + child->set_frame(child_frame); + } + } + + template <typename FUN, typename EVENT> + static void + call_children (View* parent, FUN fun, const EVENT& e) + { + assert(parent); + + View::child_iterator end = parent->child_end(); + for (View::child_iterator it = parent->child_begin(); it != end; ++it) + fun(it->get(), e); + } + void - update_view_tree (View* view, float dt) + call_key_event (View* child, const KeyEvent& event) { - if (!view) return; + if (!child) + argument_error(__FILE__, __LINE__); - view->update(dt); + bool capturing = child->capture() & View::CAPTURE_KEY; + if (capturing != event.capture) return; - View::Data::iterator end = view->self->end(); - for (View::Data::iterator it = view->self->begin(); it != end; ++it) - update_view_tree(it->get(), dt); + KeyEvent e = event; + child->on_key(&e); } void - draw_view_tree (View* view, Painter* p, coord left, coord top) + call_pointer_event (View* child, const PointerEvent& event) { - if (!view || !p) return; + if (!child) + argument_error(__FILE__, __LINE__); - const Bounds& b = view->bounds(); - left += b.x; - top += b.y; + bool capturing = child->capture() & View::CAPTURE_POINTER; + if (capturing != event.capture) return; - p->push_matrix(); - p->translate(b.x, b.y); - p->set_clip(left, top, b.width, b.height); + const Bounds& frame = child->frame(); - view->draw(p, Bounds(0, 0, b.width, b.height)); + if (!capturing) + { + bool include = false; + for (size_t i = 0; i < event.size; ++i) + { + if (frame.is_include(event[i])) + { + include = true; + break; + } + } + if (!include) return; + } - View::Data::iterator end = view->self->end(); - for (View::Data::iterator it = view->self->begin(); it != end; ++it) - draw_view_tree(it->get(), p, left, top); + PointerEvent e = event; + Point offset = frame.position(); + for (size_t i = 0; i < e.size; ++i) + e[i] -= offset; - p->pop_matrix(); + child->on_pointer(&e); + + if (!event.capture) + call_children(child, call_pointer_event, e); } + void + call_wheel_event (View* child, const WheelEvent& event) + { + if (!child) + argument_error(__FILE__, __LINE__); - View::View () + const Bounds& frame = child->frame(); + + if (!frame.is_include(event.x, event.y, event.z)) + return; + + WheelEvent e = event; + e.position() -= frame.position(); + + child->on_wheel(&e); + + call_children(child, call_wheel_event, e); + } + + + View::View (const char* name) { + if (name) self->selector().set_name(name); } View::~View () { } - bool + void View::show () { - --self->hidecount; - return true; + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + --self->hide_count; + redraw(); } - bool + void View::hide () { - ++self->hidecount; - return true; + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + ++self->hide_count; + redraw(); } bool + View::hidden () const + { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + return self->hide_count > 0; + } + + void View::redraw () { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + Window* w = window(); - return w && w->redraw(); + if (!w) return; + + w->redraw(); } - bool + void View::add_child (View* child) { - if (!child) return false; + if (!child || child == this) + argument_error(__FILE__, __LINE__); - View* parent = child->parent(); - if (parent) return parent == this; + if (!*this) + invalid_state_error(__FILE__, __LINE__); - Data::iterator it = std::find(self->begin(), self->end(), child); - if (it != self->end()) return false; + bool found = std::find(child_begin(), child_end(), child) != child_end(); + bool belong = child->parent() == this; + if (found && belong) + return; + else if (found != belong) + invalid_state_error(__FILE__, __LINE__); - if (!child->self->set_parent(this)) - return false; - - self->children()->push_back(child); - return true; + self->children().push_back(child); + set_parent(child, this); } - bool + void View::remove_child (View* child) { - if (!self->pchildren_ || !child || child->parent() != this) - return false; + if (!child || child == this) + argument_error(__FILE__, __LINE__); - Data::iterator it = std::find(self->begin(), self->end(), child); - if (it == self->end()) return false; + if (!*this) + invalid_state_error(__FILE__, __LINE__); - if (!child->self->set_parent(NULL)) - return false; + if (!self->pchildren) return; - self->pchildren_->erase(it); - return true; + child_iterator it = std::find(child_begin(), child_end(), child); + if (it == child_end()) return; + + if (child->parent() != this) + invalid_state_error(__FILE__, __LINE__); + + set_parent(child, NULL); + self->pchildren->erase(it); } - View* - View::find_child (const char* name, size_t index, bool recursive) + static void + find_all_children ( + View::ChildList* result, const View* view, const Selector& selector, bool recursive) { - if (recursive && index > 0) return NULL; - - for (Data::iterator it = self->begin(); it != self->end(); ++it) + View::const_child_iterator end = view->child_end(); + for (View::const_child_iterator it = view->child_begin(); it != end; ++it) { - if ( - strcmp((*it)->name(), name) == 0 && - index-- == 0) - { - return (View*) it->get(); - } + const View* child = it->get(); + if (!child) + invalid_state_error(__FILE__, __LINE__); - This* p = NULL; - if (recursive && (p = dynamic_cast<This*>(it->get()))) - { - View* child = p->find_child(name, 0, true); - if (child) return child; - } + if (selector.match(child->selector())) + result->push_back(*it); + + if (recursive) find_all_children(result, child, selector, true); } + } + void + View::find_children ( + ChildList* result, const Selector& selector, bool recursive) const + { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + result->clear(); + find_all_children(result, this, selector, recursive); + } + + static View::ChildList empty_children; + + View::child_iterator + View::child_begin () + { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + if (!self->pchildren) return empty_children.begin(); + return self->pchildren->begin(); + } + + View::const_child_iterator + View::child_begin () const + { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + if (!self->pchildren) return empty_children.begin(); + return self->pchildren->begin(); + } + + View::child_iterator + View::child_end () + { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + if (!self->pchildren) return empty_children.end(); + return self->pchildren->end(); + } + + View::const_child_iterator + View::child_end () const + { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + if (!self->pchildren) return empty_children.end(); + return self->pchildren->end(); + } + + Style& + View::style () + { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + return self->style; + } + + const Style& + View::style () const + { + return const_cast<View*>(this)->style(); + } + + void + View::add_style (const Style& style) + { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + self->styles().push_back(style); + } + + void + View::remove_style (const Style& style) + { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + if (!self->pstyles) return; + + style_iterator it = std::find(style_begin(), style_end(), style); + if (it == style_end()) return; + + self->styles().erase(it); + } + + Style* + View::get_style (const Selector& selector) + { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + style_iterator end = style_end(); + for (style_iterator it = style_begin(); it != end; ++it) + { + if (selector == it->selector()) + return &*it; + } + return NULL; } - const View* - View::find_child (const char* name, size_t index, bool recursive) const + const Style* + View::get_style (const Selector& selector) const { - return const_cast<This*>(this)->find_child(name, index, recursive); + return const_cast<View*>(this)->get_style(selector); } + static void + find_all_styles ( + View::StyleList* result, const View* view, const Selector& selector, bool recursive) + { + View::const_style_iterator end = view->style_end(); + for (View::const_style_iterator it = view->style_begin(); it != end; ++it) + { + if (selector.match(it->selector())) + result->push_back(*it); + } + + if (recursive) + { + View::const_child_iterator end = view->child_end(); + for (View::const_child_iterator it = view->child_begin(); it != end; ++it) + find_all_styles(result, it->get(), selector, true); + } + } + + void + View::find_styles (StyleList* result, const Selector& selector, bool recursive) const + { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + result->clear(); + find_all_styles(result, this, selector, recursive); + } + + static View::StyleList empty_styles; + + View::style_iterator + View::style_begin () + { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + if (!self->pstyles) return empty_styles.begin(); + return self->pstyles->begin(); + } + + View::const_style_iterator + View::style_begin () const + { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + if (!self->pstyles) return empty_styles.begin(); + return self->pstyles->begin(); + } + + View::style_iterator + View::style_end () + { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + if (!self->pstyles) return empty_styles.end(); + return self->pstyles->end(); + } + + View::const_style_iterator + View::style_end () const + { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + if (!self->pstyles) return empty_styles.end(); + return self->pstyles->end(); + } + + void + View::focus (bool state) + { + Window* w = window(); + if (!w) return; + + if (state) + set_focus(w, this); + else if (w->focus() == this) + set_focus(w, NULL); + } + + void + View::blur () + { + focus(false); + } + bool + View::has_focus () const + { + const Window* w = window(); + return w && w->focus() == this; + } + + void + View::resize_to_fit () + { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + Point size = content_size(); + if (size.x < 0 && size.y < 0 && size.z <= 0) return; + + Bounds b = frame(); + if (size.x >= 0) b.width = size.x; + if (size.y >= 0) b.height = size.y; + if (size.z >= 0) b.depth = size.z; + set_frame(b); + } + + Point + View::content_size () const + { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + return -1; + } + + void View::set_name (const char* name) { - self->name = name ? name : ""; - return true; + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + self->selector().set_name(name); } const char* View::name () const { - return self->name.c_str(); + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + const Selector* sel = self->pselector.get(); + return sel ? sel->name() : NULL; } - bool - View::set_bounds (coord x, coord y, coord width, coord height) + void + View::add_tag (const char* tag) { - Bounds& b = self->bounds; - b.x = x; - b.y = y; - b.width = width; - b.height = height; - return true; + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + self->selector().add_tag(tag); } - bool - View::set_bounds (const Bounds& bounds) + void + View::remove_tag (const char* tag) { - self->bounds = bounds; - return true; + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + Selector* sel = self->pselector.get(); + if (!sel) return; + + sel->remove_tag(tag); } + static Selector::TagSet empty_tags; + + View::tag_iterator + View::tag_begin () + { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + Selector* sel = self->pselector.get(); + return sel ? sel->begin() : empty_tags.begin(); + } + + View::const_tag_iterator + View::tag_begin () const + { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + const Selector* sel = self->pselector.get(); + return sel ? sel->begin() : empty_tags.begin(); + } + + View::tag_iterator + View::tag_end () + { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + Selector* sel = self->pselector.get(); + return sel ? sel->end() : empty_tags.end(); + } + + View::const_tag_iterator + View::tag_end () const + { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + const Selector* sel = self->pselector.get(); + return sel ? sel->end() : empty_tags.end(); + } + + void + View::set_selector (const Selector& selector) + { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + self->selector() = selector; + } + + Selector& + View::selector () + { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + return self->selector(); + } + + const Selector& + View::selector () const + { + static const Selector EMPTY; + + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + const Selector* sel = self->pselector.get(); + return sel ? *sel : EMPTY; + } + + void + View::set_frame (coord x, coord y, coord width, coord height) + { + set_frame(Bounds(x, y, width, height)); + } + + void + View::set_frame (const Bounds& frame) + { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + const Bounds& current = self->frame; + if (frame == current) return; + + self->frame = frame; + + FrameEvent event( + self->frame, + frame.x - current.x, frame.y - current.y, + frame.w - current.w, frame.h - current.h); + if (event.is_move()) on_move(&event); + if (event.is_resize()) on_resize(&event); + + reflow_children(this, &event); + redraw(); + } + const Bounds& - View::bounds () const + View::frame () const { - return self->bounds; + if (!*this) + invalid_state_error(__FILE__, __LINE__); + + return self->frame; } - bool - View::hidden () const + static const Point ZERO_SCROLL; + + void + View::scroll_to (coord x, coord y, coord z) { - return self->hidecount > 0; + Point old = self->scroll(); + self->scroll().reset(x, y, z); + ScrollEvent e(x, y, z, x - old.x, y - old.y, z - old.z); + on_scroll(&e); + redraw(); } + void + View::scroll_to (const Point& scroll) + { + scroll_to(scroll.x, scroll.y, scroll.z); + } + + void + View::scroll_by (coord x, coord y, coord z) + { + const Point& p = scroll(); + scroll_to(p.x + x, p.y + y, p.z + z); + } + + void + View::scroll_by (const Point& dscroll) + { + scroll_by(dscroll.x, dscroll.y, dscroll.z); + } + + const Point& + View::scroll () const + { + if (self->pscroll) + return self->scroll(); + else + return ZERO_SCROLL; + } + + void + View::set_capture (uint types) + { + if (types == self->capture) return; + + uint old = self->capture; + self->capture = types; + + bool registered = old != CAPTURE_NONE; + bool capture = types != CAPTURE_NONE; + + if (capture && !registered) + register_capture(this); + else if (!capture && registered) + unregister_capture(this); + + CaptureEvent e(~old & types, old & ~types); + on_capture(&e); + } + + uint + View::capture () const + { + return self->capture; + } + View* View::parent () { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + return self->parent; } const View* View::parent () const @@ -280,36 +1210,205 @@ } Window* View::window () { + if (!*this) + invalid_state_error(__FILE__, __LINE__); + return self->window; } const Window* View::window () const { return const_cast<View*>(this)->window(); } + Rays::Point + View::from_parent (const Rays::Point& point) const + { + not_implemented_error(__FILE__, __LINE__); + return 0; + } + + Rays::Point + View::to_parent (const Rays::Point& point) const + { + not_implemented_error(__FILE__, __LINE__); + return 0; + } + + Point + View::from_window (const Point& point) const + { + Point p = point; + for (const View* v = parent(); v; v = v->parent()) + p -= v->frame().position(); + return p; + } + + Rays::Point + View::to_window (const Rays::Point& point) const + { + not_implemented_error(__FILE__, __LINE__); + return 0; + } + + Rays::Point + View::from_screen (const Rays::Point& point) const + { + not_implemented_error(__FILE__, __LINE__); + return 0; + } + + Rays::Point + View::to_screen (const Rays::Point& point) const + { + not_implemented_error(__FILE__, __LINE__); + return 0; + } + void - View::update (float dt) + View::on_attach (Event* e) { + resize_to_fit(); } void - View::draw (Painter* p, const Bounds& b) + View::on_detach (Event* e) { + if (!e) + argument_error(__FILE__, __LINE__); } void - View::moved (coord dx, coord dy) + View::on_update (UpdateEvent* e) { + if (!e) + argument_error(__FILE__, __LINE__); } void - View::resized (coord dwidth, coord dheight) + View::on_draw (DrawEvent* e) { + if (!e) + argument_error(__FILE__, __LINE__); + } + + void + View::on_move (FrameEvent* e) + { + if (!e) + argument_error(__FILE__, __LINE__); + } + + void + View::on_resize (FrameEvent* e) + { + if (!e) + argument_error(__FILE__, __LINE__); + } + + void + View::on_scroll (ScrollEvent* e) + { + if (!e) + argument_error(__FILE__, __LINE__); + } + + void + View::on_focus (FocusEvent* e) + { + if (!e) + argument_error(__FILE__, __LINE__); + } + + void + View::on_blur (FocusEvent* e) + { + if (!e) + argument_error(__FILE__, __LINE__); + } + + void + View::on_key (KeyEvent* e) + { + if (!e) + argument_error(__FILE__, __LINE__); + + switch (e->type) + { + case KeyEvent::DOWN: on_key_down(e); break; + case KeyEvent::UP: on_key_up(e); break; + case KeyEvent::NONE: break; + } + } + + void + View::on_key_down (KeyEvent* e) + { + if (!e) + argument_error(__FILE__, __LINE__); + } + + void + View::on_key_up (KeyEvent* e) + { + if (!e) + argument_error(__FILE__, __LINE__); + } + + void + View::on_pointer (PointerEvent* e) + { + if (!e) + argument_error(__FILE__, __LINE__); + + switch (e->type) + { + case PointerEvent::DOWN: on_pointer_down(e); break; + case PointerEvent::UP: on_pointer_up(e); break; + case PointerEvent::MOVE: on_pointer_move(e); break; + case PointerEvent::NONE: break; + } + } + + void + View::on_pointer_down (PointerEvent* e) + { + if (!e) + argument_error(__FILE__, __LINE__); + } + + void + View::on_pointer_up (PointerEvent* e) + { + if (!e) + argument_error(__FILE__, __LINE__); + } + + void + View::on_pointer_move (PointerEvent* e) + { + if (!e) + argument_error(__FILE__, __LINE__); + } + + void + View::on_wheel (WheelEvent* e) + { + if (!e) + argument_error(__FILE__, __LINE__); + + //scroll_by(e->dx, e->dy, e->dz); + } + + void + View::on_capture (CaptureEvent* e) + { + if (!e) + argument_error(__FILE__, __LINE__); } View::operator bool () const { return true;