/* ui/listview.cc This file is part of the Osirion project and is distributed under the terms of the GNU General Public License version 2 */ #include "ui/listview.h" namespace ui { ListView::ListView(Widget *parent) : Widget(parent) { listview_scroll = 0.0f; listview_selecteditem = 0; set_label("listview"); set_border(true); set_background(true); listview_scrollbar = new ScrollBar(this); listview_scrollbar->set_background(false); listview_scrollbar->set_border(false); } ListView::~ListView() { } void ListView::set_scroll(float scroll) { listview_scroll = scroll; if (listview_scroll < 0) listview_scroll = 0; // calculate maximal scroll size float nb_items = 0; for (Children::iterator it = children().begin(); it != children().end(); ++it) { if ((*it) != static_cast(listview_scrollbar)) { nb_items += 1.0f; } } if (nb_items > 0.0f) { nb_items -= 1.0f; } if (listview_scroll > nb_items) { listview_scroll = nb_items; } } void ListView::inc_scroll(float scroll) { set_scroll(listview_scroll + scroll); } void ListView::dec_scroll(float scroll) { set_scroll(listview_scroll - scroll); } void ListView::resize() { listview_scrollbar->set_size(font()->height(), height()); listview_scrollbar->set_location(width() - listview_scrollbar->width(), 0); float total_height = 0; float visible_height = 0; float nb_items = 0; // reposition all children within the container for (Children::iterator it = children().begin(); it != children().end(); ++it) { if ((*it) != static_cast(listview_scrollbar)) { (*it)->set_width(width() - listview_scrollbar->width()); if (nb_items - listview_scroll < 0) { // child widget is invisible (*it)->hide(); } else if ((visible_height + (*it)->height()) > height()) { // child widget is invisible (*it)->hide(); } else { // child widget is visible (*it)->show(); (*it)->set_location(0, visible_height); visible_height += (*it)->height(); } total_height += (*it)->height(); nb_items += 1.0f; } } if (total_height > height()) { if (nb_items > 0.0f) nb_items -= 1.0f; listview_scrollbar->set_range(0.0f, nb_items); listview_scrollbar->set_value(listview_scroll); listview_scrollbar->show(); } else { for (Children::iterator it = children().begin(); it != children().end(); ++it) { if ((*it) != static_cast(listview_scrollbar)) { (*it)->set_width(width()); } } listview_scrollbar->hide(); } } void ListView::deselect() { listview_selecteditem = 0; } void ListView::select(ListItem *item) { if (!item || is_child(item)) { listview_selecteditem = item; } } void ListView::clear() { listview_scroll = 0; listview_selecteditem = 0; remove_children(); listview_scrollbar = new ScrollBar(this); listview_scrollbar->set_background(false); listview_scrollbar->set_border(false); listview_scrollbar->set_range(0.0f, 0.0f); listview_scrollbar->set_value(listview_scroll); } ListItem *ListView::add_item(const std::string & text) { return new ui::ListItem(this, text.c_str()); } bool ListView::on_emit(Widget *sender, const Event event, void *data) { if (sender == listview_scrollbar) { if (event == Widget::EventScrollBarChanged) { listview_scroll = listview_scrollbar->value(); resize(); } return true; } else if ((sender->parent() == this) && (event == Widget::EventListItemClicked)) { listview_selecteditem = static_cast(sender); emit(EventListViewChanged); return true; } return false; } bool ListView::on_mousewheel(const math::Vector2f & direction) { if (direction.y() > 0 ) { dec_scroll(1.0f); resize(); return true; } else if (direction.y() < 0) { inc_scroll(1.0f); resize(); return true; } return false; } bool compare_listitems_ascending(const Widget *first, const Widget *second) { const ListItem *firstitem = dynamic_cast(first); const ListItem *seconditem = dynamic_cast(second); if (!firstitem) return true; else if (!seconditem) return false; if (firstitem->sortkey() < seconditem->sortkey()) { return true; } else if (firstitem->sortkey() > seconditem->sortkey()) { return false; } else { return (firstitem->sortkey().length() < seconditem->sortkey().length()); } } bool compare_listitems_descending(const Widget *first, const Widget *second) { const ListItem *firstitem = dynamic_cast(first); const ListItem *seconditem = dynamic_cast(second); if (!firstitem) return true; else if (!seconditem) return false; if (firstitem->sortkey() < seconditem->sortkey()) { return false; } else if (firstitem->sortkey() > seconditem->sortkey()) { return true; } else { return (firstitem->sortkey().length() > seconditem->sortkey().length()); } } void ListView::sort(bool ascending) { if (ascending) { children().sort(compare_listitems_ascending); } else { children().sort(compare_listitems_descending); } } }