+void List::set_selected_index(int i)
+{
+ if(i>=static_cast<int>(data->size()))
+ throw out_of_range("List::set_selected_index");
+
+ if(i==sel_index || (i<0 && sel_index<0))
+ return;
+
+ if(sel_index>=0)
+ items[sel_index]->set_active(false);
+ if(i<0)
+ {
+ sel_index = -1;
+ focus_index = -1;
+ set_input_focus(nullptr);
+ signal_selection_cleared.emit();
+ }
+ else
+ {
+ sel_index = i;
+ focus_index = i;
+ items[sel_index]->set_active(true);
+ if(state&FOCUS)
+ set_input_focus(items[focus_index]);
+ signal_item_selected.emit(sel_index);
+ }
+}
+
+void List::set_selected_item(Widget *item)
+{
+ for(unsigned i=rows[first_row].first; (i<items.size() && items[i]->is_visible()); ++i)
+ if(item==items[i])
+ return set_selected_index(i);
+}
+
+void List::rebuild_special(const Part &part)
+{
+ if(part.get_name()=="slider")
+ reposition_child(slider, part);
+ else if(part.get_name()=="items")
+ {
+ SetFlag flag(ignore_slider_change);
+ reposition_items(true);
+ unsigned old_first_row = first_row;
+ unsigned old_max_scroll = max_scroll;
+ check_view_range();
+ if(first_row!=old_first_row || max_scroll!=old_max_scroll)
+ reposition_items(false);
+ }
+
+ Widget::rebuild_special(part);
+}
+
+void List::render_special(const Part &part, GL::Renderer &renderer) const
+{
+ if(part.get_name()=="items")
+ {
+ for(unsigned i=rows[first_row].first; (i<items.size() && items[i]->is_visible()); ++i)
+ items[i]->render(renderer);
+ }
+ else if(part.get_name()=="slider")
+ slider.render(renderer);
+}
+
+bool List::key_press(unsigned key, unsigned mod)
+{
+ if(key==Input::KEY_UP && mod==MOD_CTRL)
+ move_focus(NAV_UP, false);
+ else if(key==Input::KEY_DOWN && mod==MOD_CTRL)
+ move_focus(NAV_DOWN, false);
+ else
+ return false;
+
+ return true;