1 #include <msp/core/algorithm.h>
2 #include <msp/core/maputils.h>
5 #include "draghandle.h"
10 #include "indicator.h"
15 #include "progressbar.h"
26 TypeRegistry<Panel::Loader::AddChildType, Panel::Loader &> Panel::widget_registry;
27 bool Panel::widget_registry_init_done = false;
31 input_type = INPUT_NAVIGATION;
34 Layout &Panel::get_or_create_layout()
38 layout = make_unique<Layout>();
39 layout->set_container(*this);
45 void Panel::autosize_special(const Part &part, Geometry &ageom) const
47 if(part.get_name()=="children" && layout)
48 layout->autosize(ageom);
51 void Panel::render_special(const Part &part, GL::Renderer &renderer) const
53 if(part.get_name()=="children")
55 for(const unique_ptr<Child> &c: children)
56 if(c->widget->is_visible())
57 c->widget->render(renderer);
61 bool Panel::navigate(Navigation nav)
63 if(Container::navigate(nav))
66 if(nav==NAV_UP || nav==NAV_DOWN || nav==NAV_LEFT || nav==NAV_RIGHT)
68 int nav_x = (nav==NAV_RIGHT ? 1 : nav==NAV_LEFT ? -1 : 0);
69 int nav_y = (nav==NAV_UP ? 1 : nav==NAV_DOWN ? -1 : 0);
71 int origin_x, origin_y, origin_dim;
74 const Geometry &fgeom = input_focus->get_geometry();
75 origin_x = fgeom.x+(nav_x*0.5+0.5)*fgeom.w;
76 origin_y = fgeom.y+(nav_y*0.5+0.5)*fgeom.h;
77 origin_dim = abs(nav_x)*fgeom.h+abs(nav_y)*fgeom.w;
81 origin_x = geom.w*(0.5-nav_x*0.5);
82 origin_y = geom.h*(0.5-nav_y*0.5);
83 origin_dim = abs(nav_x)*geom.h+abs(nav_y)*geom.w;
86 if(pointer_grabbed && pointer_focus==input_focus)
89 Widget *sibling = find_next_child(origin_x, origin_y, origin_dim, nav_x, nav_y);
90 if(!sibling && input_focus)
92 const Geometry &fgeom = input_focus->get_geometry();
93 origin_x -= fgeom.w*(nav_x*0.5);
94 origin_y -= fgeom.h*(nav_y*0.5);
95 sibling = find_next_child(origin_x, origin_y, origin_dim, nav_x, nav_y);
100 set_input_focus(sibling);
101 if(Panel *panel = dynamic_cast<Panel *>(sibling))
102 panel->navigate(nav);
106 else if(nav==NAV_NEXT || nav==NAV_PREVIOUS)
108 auto i = find(nav_order, input_focus);
112 if(i!=nav_order.end())
114 if(i==nav_order.end())
115 i = nav_order.begin();
119 if(i==nav_order.begin())
132 Widget *Panel::find_next_child(int origin_x, int origin_y, int origin_dim, int nav_x, int nav_y) const
134 Widget *sibling = nullptr;
136 for(const unique_ptr<Child> &c: children)
138 if(c->widget==input_focus || !c->widget->is_focusable())
141 const Geometry &cgeom = c->widget->get_geometry();
142 int dx = compute_delta(cgeom.x, cgeom.w, origin_x, origin_dim, nav_x);
143 int dy = compute_delta(cgeom.y, cgeom.h, origin_y, origin_dim, nav_y);
146 if(nav_y && nav_y*dy>=0)
147 score = nav_y*dy+abs(dx)*4;
148 else if(nav_x && nav_x*dx>=0)
149 score = nav_x*dx+abs(dy)*4;
151 if(score>=0 && (!sibling || score<best_score))
161 int Panel::compute_delta(int pos, int dim, int origin_pos, int origin_dim, int nav)
164 return pos+dim-origin_pos;
166 return pos-origin_pos;
167 else if(pos+dim<origin_pos-origin_dim/2)
168 return pos+dim+origin_dim/2-origin_pos;
169 else if(pos>origin_pos+origin_dim/2)
170 return pos-origin_pos-origin_dim/2;
175 void Panel::on_size_change()
181 void Panel::on_child_added(Widget &wdg)
183 if(wdg.get_input_type()!=INPUT_NONE)
184 nav_order.push_back(&wdg);
188 layout->add_widget(wdg);
189 signal_autosize_changed.emit();
193 void Panel::on_child_removed(Widget &wdg)
195 auto i = std::remove(nav_order.begin(), nav_order.end(), &wdg);
196 if(i!=nav_order.end())
197 nav_order.erase(i, nav_order.end());
201 layout->remove_widget(wdg);
202 signal_autosize_changed.emit();
207 Panel::Loader::Loader(Panel &p, map<string, Widget *> &m):
208 DataFile::DerivedObjectLoader<Panel, Widget::Loader>(p),
212 if(!widget_registry_init_done)
214 widget_registry_init_done = true;
215 register_child_type<Button>("button");
216 register_child_type<DragHandle>("draghandle");
217 register_child_type<Dropdown>("dropdown");
218 register_child_type<Entry>("entry");
219 register_child_type<HSlider>("hslider");
220 register_child_type<Image>("image");
221 register_child_type<Indicator>("indicator");
222 register_child_type<Label>("label");
223 register_child_type<List>("list");
224 register_child_type<Panel>("panel");
225 register_child_type<ProgressBar>("progressbar");
226 register_child_type<Toggle>("toggle");
227 register_child_type<VSlider>("vslider");
230 add("column", &Loader::arrangement<Column>);
231 add("constraint",&Loader::constraint);
232 add("expand", &Loader::expand);
233 add("ghost", &Loader::ghost);
234 add("gravity", &Loader::gravity);
235 add("grid", &Loader::grid);
236 add("layout", &Loader::layout);
237 add("row", &Loader::arrangement<Row>);
238 add("stack", &Loader::arrangement<Stack>);
239 widget_registry.invoke_all(*this);
242 Widget &Panel::Loader::get_last_widget()
245 throw logic_error("no widget loaded");
251 void Panel::Loader::arrangement()
253 T arr(obj.get_or_create_layout());
254 ArrangedLoader<T> ldr(*this, arr);
258 void Panel::Loader::constraint(Layout::ConstraintType type, const string &n)
260 Widget &src = get_last_widget();
261 Widget &tgt = *get_item(wdg_map, n);
262 obj.get_or_create_layout().add_constraint(src, type, tgt);
265 void Panel::Loader::expand(bool h, bool v)
267 obj.get_or_create_layout().set_expand(get_last_widget(), h, v);
270 void Panel::Loader::ghost(bool g)
272 obj.get_or_create_layout().set_ghost(get_last_widget(), g);
275 void Panel::Loader::gravity(int h, int v)
277 obj.get_or_create_layout().set_gravity(get_last_widget(), h, v);
280 void Panel::Loader::grid(size_t cols)
282 Grid grd(obj.get_or_create_layout(), cols);
283 ArrangedLoader<Grid> ldr(*this, grd);
287 void Panel::Loader::layout()
289 Layout::Loader ldr(obj.get_or_create_layout(), wdg_map);
294 void Panel::Loader::unnamed_child<Panel>()
296 unique_ptr<Panel> pnl = make_unique<Panel>();
297 load_sub(*pnl, wdg_map);
299 last_widget = pnl.release();
304 Panel::ArrangedLoader<T>::ArrangedLoader(Loader &ldr, T &arr):
307 add_auxiliary_loader(ldr);
308 add_auxiliary_loader(arr_loader);