3 * (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
4 * economic rights: Technische Universität Dresden (Germany)
6 * This file is part of TUD:OS and distributed under the terms of the
7 * GNU General Public License 2.
8 * Please see the COPYING-GPL-2 file for details.
12 #include <l4/mag-gfx/canvas>
13 #include <l4/mag-gfx/clip_guard>
14 #include <l4/mag-gfx/font>
16 #include <l4/cxx/observer>
18 #include <l4/re/event_enums.h>
20 namespace Mag_server {
22 template< typename C >
23 class Menu : private cxx::Observer
27 typedef typename C::Value_type Item;
28 typedef typename C::Iterator Iterator;
29 typedef typename C::Const_iterator Const_iterator;
32 Core_api const *_core;
34 Content const *_content;
35 Const_iterator _current;
44 Font const *_font() const { return _core->label_font(); }
45 View_stack *_vstack() const { return _core->user_state()->vstack(); }
48 int scroll_button_height() const { return 15; }
49 int item_sep() const { return 2; }
50 int menu_border() const { return 4; }
51 int min_width() const { return 180; }
53 Menu(Core_api const *core, View *view, Content const *content)
54 : _view(view), _core(core), _content(content), _current(content->end()),
55 _cell(min_width(), _font()->str_h("X") + 2 * item_sep()), _height(0),
56 _offset(0), _scroll(false), _speed(0)
59 Area calc_geometry(Area const &size);
60 Const_iterator find(Point const &pos, Rect *cell, int *y);
61 bool find(Const_iterator const &x, Rect *cell, int *y);
63 void draw(Canvas *canvas, Point const &pos) const;
64 Const_iterator handle_event(Hid_report *e, Point const &mouse);
68 int h = _size.h() - 2 * scroll_button_height();
69 _offset = std::max(0, std::min(_height - h, _offset + dist));
72 void optimize_offset(int current_pos)
81 int h = _size.h() - 2 * scroll_button_height();
82 int o_min = std::max(current_pos + _cell.h() - h, 0);
83 int o_max = std::min(current_pos, _height - h);
85 if (_offset <= o_max && _offset >= o_min)
96 template< typename F >
97 Const_iterator _find(Rect const &_bb, F const &f) const;
105 Find_for_pos(Point const &p, Rect *cell, int *offs)
106 : pos(p), cell(cell), offs(offs) {}
108 bool valid(Rect const &bb) const { return bb.contains(pos); }
109 bool operator () (Const_iterator const &, Rect const &bb, int y) const
111 if (!bb.contains(pos))
126 Find_item(Const_iterator const &item, Rect *cell, int *offs)
127 : item(item), cell(cell), offs(offs) {}
129 bool valid(Rect const &) const { return true; }
130 bool operator () (Const_iterator const &e, Rect const &bb, int y) const
145 Draw_item(Draw_item const &);
150 mutable Clip_guard g;
152 Draw_item(Menu const *m, Canvas *c) : canvas(c), menu(m) {}
153 bool valid(Rect const &bb) const
156 return canvas->clip_valid();
159 bool operator () (Const_iterator const &e, Rect br, int) const
161 Rgb32::Color lcol = e->ignore() ? Rgb32::Color(255, 200, 0) : Rgb32::White;
162 Rgb32::Color bcol = e == menu->_current ? Rgb32::Color(99, 120, 180) : Rgb32::Color(99, 99, 88);
163 canvas->draw_box(br, bcol);
164 br = br.offset(menu->menu_border(), menu->item_sep(), -menu->menu_border(), -menu->item_sep());
165 Clip_guard g(canvas, br);
166 canvas->draw_string(br.p1(), menu->_font(), lcol, e->label());
171 // handle timer ticks
177 Menu<C>::calc_geometry(Area const &max_size)
179 Area fs(min_width(), 0); //2 * menu_border());
180 bool cf = _current == _content->end();
182 for (Const_iterator e = _content->begin(); e != _content->end(); ++e)
184 int w = _font()->str_w(e->label()) + 2 * menu_border();
194 fs.h(fs.h() + _cell.h());
197 /* the current item is gone so select none */
199 _current = _content->end();
202 if (fs.h() > max_size.h())
210 if (_current != _content->end())
213 if (fs.w() > max_size.w())
222 template< typename C >
223 template< typename F >
224 typename Menu<C>::Const_iterator
225 Menu<C>::_find(Rect const &_bb, F const &f) const
229 bb = _bb.offset(0, scroll_button_height(), 0, -scroll_button_height());
232 return _content->end();
236 for (Const_iterator e = _content->begin(); e != _content->end(); ++e)
238 int ny = y + _cell.h();
240 if (y - _offset > bb.h())
245 Rect br(Point(bb.x1(), bb.y1() + y - _offset), _cell);
251 return _content->end();
255 template< typename C >
256 typename Menu<C>::Const_iterator
257 Menu<C>::find(Point const &pos, Rect *cell, int *y)
258 { return _find(Rect(Point(), _size), Find_for_pos(pos, cell, y)); }
260 template< typename C >
262 Menu<C>::find(Const_iterator const &x, Rect *cell, int *y)
263 { return _find(Rect(Point(), _size), Find_item(x, cell, y)) != _content->end(); }
265 template< typename C >
267 Menu<C>::draw(Canvas *canvas, Point const &pos) const
269 using Mag_gfx::Clip_guard;
272 Clip_guard g(canvas, bb);
274 if (!canvas->clip_valid())
279 Rect s(pos, Area(_size.w(), scroll_button_height()));
280 canvas->draw_box(s, Rgb32::Color(99, 99, 88)); //, 220));
281 s = s + Point(0, _size.h() - scroll_button_height());
282 canvas->draw_box(s, Rgb32::Color(99, 99, 88)); //, 220));
285 // Hm, make g++ 4.2 happy, that tries to call the copy ctor
286 // in the case of directly using a temporary
287 Draw_item di(this, canvas);
291 template< typename C >
292 typename Menu<C>::Const_iterator
293 Menu<C>::handle_event(Hid_report *e, Point const &mouse)
295 Valuator<int> const *abs = e->get_vals(3);
296 if (abs && abs->get(0).valid())
300 int const sbh = scroll_button_height();
302 if ((speed = sbh - mouse.y()) > 0)
305 if (!cxx::H_list<Observer>::in_list(this))
306 _core->get_ticks(this);
308 else if ((speed = sbh - (_size.h() - mouse.y())) > 0)
311 if (!cxx::H_list<Observer>::in_list(this))
312 _core->get_ticks(this);
316 cxx::H_list<Observer>::remove(this);
321 return _content->end();
325 Const_iterator s = find(mouse, &nr, &ny);
330 bool refresh_cr = false;
331 if (_current != _content->end() && find(_current, &cr, &cy))
336 int old_offs = _offset;
338 if (_current != _content->end())
341 if (old_offs != _offset)
342 _vstack()->refresh_view(_view, 0, *_view);
346 _vstack()->refresh_view(_view, 0, cr + _view->p1());
348 if (s != _content->end())
349 _vstack()->refresh_view(_view, 0, nr + _view->p1());
354 Hid_report::Key_event const *btn_left = e->find_key_event(L4RE_BTN_LEFT);
355 if (btn_left && btn_left->value == 0)
359 return find(mouse, &nr, &ny);
362 return _content->end();
365 template< typename C >
370 cxx::H_list<Observer>::remove(this);
375 _vstack()->refresh_view(_view, 0, *_view);
377 cxx::H_list<Observer>::remove(this);