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;