1 #include <msp/gl/matrix.h>
2 #include <msp/gl/meshbuilder.h>
16 data(new BasicListData<string>),
22 List::List(ListData &d):
37 observer = new DataObserver(*this);
41 slider.signal_value_changed.connect(sigc::mem_fun(this, &List::slider_value_changed));
56 void List::autosize_rows(unsigned n)
65 const Sides &margin = items_part->get_margin();
66 const GL::Font &font = style->get_font();
67 float font_size = style->get_font_size();
70 unsigned n_items = data->size();
71 for(unsigned i=0; i<n_items; ++i)
73 unsigned w = static_cast<unsigned>(font.get_string_width(data->get_string(i))*font_size);
74 max_w = max(max_w, w);
77 geom.w = max(geom.w, max_w+margin.left+margin.right);
78 geom.h = max(geom.h, n*row_height+margin.top+margin.bottom);
81 if(const Part *slider_part = style->get_part("slider"))
83 Geometry sgeom = slider_part->get_geometry();
84 if(!sgeom.w || !sgeom.h)
88 sgeom.w = slider.get_geometry().w;
90 sgeom.h = slider.get_geometry().h;
93 const Sides &margin = slider_part->get_margin();
94 geom.w = max(geom.w, sgeom.w+margin.left+margin.right);
95 geom.h = max(geom.h, sgeom.h+margin.top+margin.bottom);
104 void List::autosize_all()
106 autosize_rows(data->size());
109 void List::set_data(ListData &d)
117 observer = new DataObserver(*this);
122 void List::items_changed()
125 signal_autosize_changed.emit();
129 void List::set_selected_index(int i)
133 else if(i<static_cast<int>(data->size()))
136 signal_item_selected.emit(sel_index);
140 throw out_of_range("List::set_selected_index");
143 void List::rebuild_special(const Part &part, CachedPart &cache)
145 if(part.get_name()=="items")
147 const Sides &margin = part.get_margin();
148 Geometry pgeom = geom;
149 pgeom.h = row_height+margin.top+margin.bottom;
151 const GL::Font &font = style->get_font();
152 cache.texture = &font.get_texture();
155 GL::MeshBuilder bld(*cache.mesh);
156 bld.color(style->get_font_color());
157 bld.matrix() *= GL::Matrix::translation(margin.left, geom.h-pgeom.h-font.get_descent()*style->get_font_size(), 0);
159 for(unsigned i=0; (i<n_visible && first+i<data->size()); ++i)
162 bld.matrix() *= GL::Matrix::translation(0, -static_cast<int>(row_height), 0);
164 GL::MatrixStack::Push _pushm(bld.matrix());
165 bld.matrix() *= GL::Matrix::scaling(style->get_font_size());
167 style->get_font().build_string(data->get_string(first+i), bld);
170 else if(part.get_name()=="selection")
172 if(sel_index>=static_cast<int>(first) && sel_index<static_cast<int>(first+n_visible))
174 const Sides &margin = part.get_margin();
176 Geometry pgeom = geom;
177 pgeom.h = row_height;
178 pgeom.w -= margin.left+margin.right;
180 Geometry rgeom = part.get_geometry();
181 rgeom.y += geom.h-margin.top-row_height*(sel_index-first+1);
182 rgeom.x += margin.left;
183 part.get_alignment().apply(rgeom, pgeom);
185 cache.texture = part.get_graphic(state)->get_texture();
188 GL::MeshBuilder bld(*cache.mesh);
189 bld.matrix() *= GL::Matrix::translation(rgeom.x, rgeom.y, 0);
190 part.get_graphic(state)->build(rgeom.w, rgeom.h, bld);
197 void List::render_special(const Part &part, GL::Renderer &renderer) const
199 if(part.get_name()=="slider")
200 slider.render(renderer);
203 void List::button_press(int x, int y, unsigned btn)
205 Container::button_press(x, y, btn);
206 if(!click_focus && btn==1)
209 y += items_part->get_margin().top;
211 unsigned i = (geom.h-1-y)/row_height;
212 if(i<n_visible && first+i<data->size())
216 signal_item_selected.emit(sel_index);
222 void List::on_geometry_change()
229 void List::on_style_change()
239 items_part = style->get_part("items");
241 const GL::Font &font = style->get_font();
242 row_height = static_cast<unsigned>((font.get_ascent()-font.get_descent())*style->get_font_size());
247 void List::reposition_slider()
252 if(const Part *slider_part = style->get_part("slider"))
254 Geometry sgeom = slider_part->get_geometry();
255 slider_part->get_alignment().apply(sgeom, geom, slider_part->get_margin());
256 slider.set_geometry(sgeom);
260 void List::check_view_range()
265 const Sides &margin = items_part->get_margin();
266 h -= margin.top+margin.bottom;
269 n_visible = h/row_height;
271 if(first+n_visible>data->size())
273 if(data->size()>n_visible)
274 first = data->size()-n_visible;
279 if(data->size()>n_visible)
281 slider.set_range(0, data->size()-n_visible);
282 slider.set_value(data->size()-n_visible-first);
286 slider.set_range(0, 0);
291 void List::slider_value_changed(double value)
293 if(data->size()>n_visible)
295 first = data->size()-n_visible-static_cast<unsigned>(value);
301 List::DataObserver::DataObserver(List &l):
304 list.data->signal_item_added.connect(sigc::mem_fun(this, &DataObserver::item_added));
305 list.data->signal_item_removed.connect(sigc::mem_fun(this, &DataObserver::item_removed));
306 list.data->signal_cleared.connect(sigc::mem_fun(this, &DataObserver::cleared));
307 list.data->signal_refresh_strings.connect(sigc::mem_fun(this, &DataObserver::refresh_strings));
310 void List::DataObserver::item_added(unsigned i)
312 if(list.sel_index>=static_cast<int>(i))
315 list.items_changed();
318 void List::DataObserver::item_removed(unsigned i)
320 if(list.sel_index>static_cast<int>(i))
322 else if(list.sel_index==static_cast<int>(i))
325 list.items_changed();
328 void List::DataObserver::cleared()
331 list.items_changed();
334 void List::DataObserver::refresh_strings()
336 list.items_changed();
340 List::Loader::Loader(List &l):
343 add("item", &Loader::item);
346 void List::Loader::item(const string &v)
348 dynamic_cast<BasicListData<string> &>(*dynamic_cast<List &>(obj).data).append(v);