/* ui/widget.cc This file is part of the Osirion project and is distributed under the terms of the GNU General Public License version 2 */ #include "auxiliary/functions.h" #include "sys/sys.h" #include "ui/paint.h" #include "ui/ui.h" #include "ui/widget.h" #include namespace ui { Widget::Widget(Widget *parent) { widget_focus = false; widget_visible = true; widget_border = true; widget_background = false; widget_enabled = true; widget_palette = 0; widget_font = 0; widget_label.assign("widget"); if (!parent) { widget_parent = root(); } else { widget_parent = parent; } if (widget_parent) widget_parent->add_child(this); } Widget::~Widget() { remove_children(); } void Widget::remove_children() { for (Children::iterator it = widget_children.begin(); it != widget_children.end(); it++) { delete(*it); (*it) = 0; } widget_children.clear(); } bool Widget::is_child(const Widget *widget) const { for (Children::const_iterator it = widget_children.begin(); it != widget_children.end(); it++) { if (widget == (*it)) return true; } return false; } size_t Widget::list(const size_t indent, const bool visible_only) const { if (visible_only && !visible()) return 0; print(indent); size_t n = 1; for (Children::const_iterator it = widget_children.begin(); it != widget_children.end(); it++) { n += (*it)->list(indent + 1, visible_only); } return n; } void Widget::print(const size_t indent) const { if (indent) { std::string marker; if (!widget_enabled) { marker.assign("^B- "); } else if (widget_focus) { marker.assign("^B* "); } else { marker.assign(" "); } if (widget_visible) { marker.append("^N"); } else { marker.append("^D"); } con_print << aux::pad_left(marker, indent*2) << label() << std::endl; } } const Palette *Widget::palette() const { if (widget_palette) { return widget_palette; } else { return parent()->palette(); } } const Font *Widget::font() const { if (widget_font) { return widget_font; } else { return parent()->font(); } } void Widget::lower() { if (!parent()) return; Children::iterator it = parent()->find_child(this); if (it != parent()->children().end()) { parent()->children().erase(it); parent()->children().push_front(this); } } void Widget::raise() { if (!parent()) return; Children::iterator it = parent()->find_child(this); if (it != parent()->children().end()) { parent()->children().erase(it); parent()->children().push_back(this); } } void Widget::set_focus() { if (!parent()) { widget_focus = true; return; } for (Children::iterator it = parent()->children().begin(); it != parent()->children().end(); it++) { (*it)->widget_focus = false; } widget_focus = true; } void Widget::show() { widget_visible = true; } void Widget::hide() { widget_visible = false; if (parent() && focus()) { Widget *sibling = next_sibling(); while (sibling && (sibling != this) && !sibling->visible()) { sibling = sibling->next_sibling(); } if (sibling) sibling->set_focus(); } /* if (parent() && focus()) { Widget::Children::reverse_iterator it = parent()->children().rbegin(); while (it != parent()->children().rend()) { Widget *w = (*it); if (w != this && w->visible()) { widget_focus = false; w->widget_focus = true; it = parent()->children().rend(); } else { it++; } } } */ } void Widget::set_visible(const bool visible) { if (visible) show(); else hide(); } void Widget::enable() { widget_enabled = true; } void Widget::disable() { widget_enabled = false; } void Widget::set_enabled(const bool enabled) { if (enabled) enable(); else disable(); } void Widget::set_border(const bool border) { widget_border = border; } void Widget::set_background(const bool background) { widget_background = background; } void Widget::set_label(const std::string & label) { widget_label.assign(label); aux::to_label(widget_label); } void Widget::set_label(const char *label) { if (label) { widget_label.assign(label); aux::to_label(widget_label); } else { widget_label.clear(); } } void Widget::set_palette(const Palette *palette) { widget_palette = palette; } void Widget::set_font(const Font *font) { widget_font = font; } void Widget::set_geometry(const float x, const float y, const float w, const float h) { widget_location.assign(x, y); widget_size.assign(w, h); } void Widget::set_geometry(const math::Vector2f &location, const math::Vector2f &size) { widget_location.assign(location); widget_size.assign(size); } void Widget::set_location(const float x, const float y) { widget_location.assign(x, y); } void Widget::set_location(const math::Vector2f &location) { widget_location.assign(location); } void Widget::set_size(const float w, const float h) { widget_size.assign(w, h); } void Widget::set_size(const math::Vector2f &size) { widget_size.assign(size); } void Widget::set_width(const float w) { widget_size[0] = w; } void Widget::set_height(const float h) { widget_size[1] = h; } Widget *Widget::next_sibling() { if (!parent() || (parent()->children().size() < 2)) { return 0; } // find this widget in the parent's children Children::iterator it = parent()->children().begin(); while (it != parent()->children().end() && ((*it) != this)) { it++; } // assert this widget is a child of its parent assert (it != parent()->children().end()); // next sibling it++; if (it == parent()->children().end()) { it = parent()->children().begin(); } if ((*it) == this) { return 0; } else { return (*it); } } Widget::Children::iterator Widget::find_child(Widget *child) { Children::iterator it; for (it = widget_children.begin(); it != widget_children.end(); it++) { if ((*it) == child) return it; } return it; } void Widget::add_child(Widget *child) { Children::iterator it = find_child(child); if (it == widget_children.end()) { widget_children.push_back(child); } } void Widget::remove_child(Widget *child) { Children::iterator it = find_child(child); if (it != widget_children.end()) { Widget *w = (*it); w->widget_parent = 0; delete(w); widget_children.erase(it); } } Widget *Widget::find_input_focus() { if (!visible() || !widget_focus) return 0; for (Children::reverse_iterator rit = widget_children.rbegin(); rit != widget_children.rend(); ++rit) { Widget *w = (*rit); if (w->visible() && w->enabled() && w->widget_focus) { Widget *f = w->find_input_focus(); if (f) return f; } } // no child with input focus return this; } Widget *Widget::find_visible_child(const Widget *widget) { if (!visible()) return 0; if (this == widget) return this; // search in reverse drawing order for (Children::reverse_iterator rit = widget_children.rbegin(); rit != widget_children.rend(); ++rit) { Widget *f = (*rit)->find_visible_child(widget); if (f) { return f; } } return 0; } Widget *Widget::find_mouse_focus(const math::Vector2f & pos) { // this widget is not visible if (!visible() || !size().contains(pos)) return 0; // reverse-iterate children for (Children::reverse_iterator rit = widget_children.rbegin(); rit != widget_children.rend(); ++rit) { Widget *w = (*rit); if (w->visible() && w->enabled()) { Widget *f = w->find_mouse_focus(pos - w->location()); if (f) return f; } } // no child with mouse focus return this; } bool Widget::has_mouse_focus() const { return (root()->mouse_focus() == this); } bool Widget::has_input_focus() const { return (root()->input_focus() == this); } /* -- event distributors ------------------------------------------- */ bool Widget::event_emit(Widget *sender, const Event event, void *data) // Unhandled events are sent to the parent widget { if (disabled()) return false; if (on_emit(sender, event, data)) { return true; } else if (parent()) { return (parent()->event_emit(sender, event, data)); } else { return false; } } bool Widget::event_key(const bool pressed, const int key, const unsigned int modifier) // Unhandled key events are sent to the parent widget { bool handled = false; if (enabled()) { if (pressed) { handled = on_keypress(key, modifier); } else { handled = on_keyrelease(key, modifier); } } if (!handled && parent()) handled = parent()->event_key(pressed, key, modifier); return handled; } void Widget::event_mouse(const math::Vector2f & cursor) { if (disabled()) return; math::Vector2f local_cursor = to_local_coords(cursor); if (root()->mouse_focus() != this) { on_mouseover(local_cursor); } on_mousemove(local_cursor); } bool Widget::event_mouse_button(const bool pressed, const unsigned int button) { bool handled = false; if (enabled()) { if (pressed) { handled = on_mousepress(button); } else { handled = on_mouserelease(button); } } if (!handled && parent()) handled = parent()->event_mouse_button(pressed, button); return handled; } bool Widget::event_mouse_wheel(const math::Vector2f & direction) { bool handled = false; if (enabled()) { handled = on_mousewheel(direction); } if (!handled && parent()) handled = parent()->event_mouse_wheel(direction); return handled; } void Widget::event_draw() { if (!visible()) return; if (widget_background) draw_background(); draw(); for (Children::iterator it = widget_children.begin(); it != widget_children.end(); it++) { if ((*it)->visible()) (*it)->event_draw(); } if (widget_border) draw_border(); if (debug()) draw_debug(); } void Widget::event_resize() { //con_debug << "event_resize in " << label() << std::endl(); resize(); for (Children::iterator it = widget_children.begin(); it != widget_children.end(); it++) { (*it)->event_resize(); } } /* -- event handlers ----------------------------------------------- */ void Widget::on_mouseover(const math::Vector2f &cursor) { return; } void Widget::on_mousemove(const math::Vector2f &cursor) { return; } bool Widget::on_mousepress(const unsigned int button) { return false; } bool Widget::on_mouserelease(const unsigned int button) { return false; } bool Widget::on_mousewheel(const math::Vector2f & direction) { return false; } bool Widget::on_keypress(const int key, const unsigned int modifier) { return false; } bool Widget::on_keyrelease(const int key, const unsigned int modifier) { return false; } bool Widget::on_emit(Widget *sender, const Event event, void *data) { return false; } /* -- draw functions ----------------------------------------------- */ void Widget::draw_debug() { Paint::set_color(1.0f, 0.0f, 1.0f, 0.5f); Paint::draw_border(global_location(), size()); } void Widget::draw_background() { //Paint::set_color(palette()->background()); //Paint::draw_rectangle(global_location(), size()); Paint::draw_material(global_location(), size(), "ui/background"); } void Widget::draw_border() { Paint::set_color(palette()->border()); Paint::draw_border(global_location(), size()); } void Widget::draw() { } void Widget::resize() { } }