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::Item Item;
30 Core_api const *_core;
32 Content const *_content;
42 Font const *_font() const { return _core->label_font(); }
43 View_stack *_vstack() const { return _core->user_state()->vstack(); }
46 int scroll_button_height() const { return 15; }
47 int item_sep() const { return 2; }
48 int menu_border() const { return 4; }
49 int min_width() const { return 180; }
51 Menu(Core_api const *core, View *view, Content const *content)
52 : _view(view), _core(core), _content(content), _current(0),
53 _cell(min_width(), _font()->str_h("X") + 2 * item_sep()), _height(0),
54 _offset(0), _scroll(false), _speed(0)
57 Area calc_geometry(Area const &size);
58 Item *find(Point const &pos, Rect *cell, int *y);
59 bool find(Item const *x, Rect *cell, int *y);
61 void draw(Canvas *canvas, Point const &pos) const;
62 Item *handle_event(L4Re::Event_buffer::Event const &e, Point const &mouse);
66 int h = _size.h() - 2 * scroll_button_height();
67 _offset = std::max(0, std::min(_height - h, _offset + dist));
70 void optimize_offset(int current_pos)
79 int h = _size.h() - 2 * scroll_button_height();
80 int o_min = std::max(current_pos + _cell.h() - h, 0);
81 int o_max = std::min(current_pos, _height - h);
83 if (_offset <= o_max && _offset >= o_min)
94 template< typename F >
95 Item *_find(Rect const &_bb, F const &f) const;
103 Find_for_pos(Point const &p, Rect *cell, int *offs)
104 : pos(p), cell(cell), offs(offs) {}
106 bool valid(Rect const &bb) const { return bb.contains(pos); }
107 bool operator () (Item *, Rect const &bb, int y) const
109 if (!bb.contains(pos))
124 Find_item(Item const *item, Rect *cell, int *offs)
125 : item(item), cell(cell), offs(offs) {}
127 bool valid(Rect const &) const { return true; }
128 bool operator () (Item *e, Rect const &bb, int y) const
143 Draw_item(Draw_item const &);
148 mutable Clip_guard g;
150 Draw_item(Menu const *m, Canvas *c) : canvas(c), menu(m) {}
151 bool valid(Rect const &bb) const
154 return canvas->clip_valid();
157 bool operator () (Item *e, Rect br, int) const
159 Rgb32::Color lcol = e->ignore() ? Rgb32::Color(255, 200, 0) : Rgb32::White;
160 Rgb32::Color bcol = e == menu->_current ? Rgb32::Color(99, 120, 180) : Rgb32::Color(99, 99, 88);
161 canvas->draw_box(br, bcol);
162 br = br.offset(menu->menu_border(), menu->item_sep(), -menu->menu_border(), -menu->item_sep());
163 Clip_guard g(canvas, br);
164 canvas->draw_string(br.p1(), menu->_font(), lcol, e->label());
169 // handle timer ticks
175 Menu<C>::calc_geometry(Area const &max_size)
177 Area fs(min_width(), 0); //2 * menu_border());
180 for (Item *e = _content->first(); e; e = _content->next(e))
182 int w = _font()->str_w(e->label()) + 2 * menu_border();
192 fs.h(fs.h() + _cell.h());
195 /* the current item is gone so select none */
200 if (fs.h() > max_size.h())
211 if (fs.w() > max_size.w())
220 template< typename C >
221 template< typename F >
222 typename Menu<C>::Item *
223 Menu<C>::_find(Rect const &_bb, F const &f) const
227 bb = _bb.offset(0, scroll_button_height(), 0, -scroll_button_height());
234 for (Item *e = _content->first(); e; e = _content->next(e))
236 int ny = y + _cell.h();
238 if (y - _offset > bb.h())
243 Rect br(Point(bb.x1(), bb.y1() + y - _offset), _cell);
253 template< typename C >
254 typename Menu<C>::Item *
255 Menu<C>::find(Point const &pos, Rect *cell, int *y)
256 { return _find(Rect(Point(), _size), Find_for_pos(pos, cell, y)); }
258 template< typename C >
260 Menu<C>::find(Item const *x, Rect *cell, int *y)
261 { return _find(Rect(Point(), _size), Find_item(x, cell, y)); }
263 template< typename C >
265 Menu<C>::draw(Canvas *canvas, Point const &pos) const
267 using Mag_gfx::Clip_guard;
270 Clip_guard g(canvas, bb);
272 if (!canvas->clip_valid())
277 Rect s(pos, Area(_size.w(), scroll_button_height()));
278 canvas->draw_box(s, Rgb32::Color(99, 99, 88)); //, 220));
279 s = s + Point(0, _size.h() - scroll_button_height());
280 canvas->draw_box(s, Rgb32::Color(99, 99, 88)); //, 220));
283 // Hm, make g++ 4.2 happy, that tries to call the copy ctor
284 // in the case of directly using a temporary
285 Draw_item di(this, canvas);
289 template< typename C >
290 typename Menu<C>::Item *
291 Menu<C>::handle_event(L4Re::Event_buffer::Event const &e, Point const &mouse)
293 if (e.payload.type == L4RE_EV_ABS && e.payload.code == 1)
297 int const sbh = scroll_button_height();
299 if ((speed = sbh - mouse.y()) > 0)
303 _core->get_ticks(this);
305 else if ((speed = sbh - (_size.h() - mouse.y())) > 0)
309 _core->get_ticks(this);
313 static_cast<Observer*>(this)->l_remove();
322 Item const *s = find(mouse, &nr, &ny);
327 bool refresh_cr = false;
328 if (_current && find(_current, &cr, &cy))
333 int old_offs = _offset;
338 if (old_offs != _offset)
339 _vstack()->refresh_view(_view, 0, *_view);
343 _vstack()->refresh_view(_view, 0, cr + _view->p1());
346 _vstack()->refresh_view(_view, 0, nr + _view->p1());
351 if (e.payload.type == L4RE_EV_KEY && e.payload.code == L4RE_BTN_LEFT
352 && e.payload.value == 0)
356 return find(mouse, &nr, &ny);
362 template< typename C >
367 static_cast<Observer*>(this)->l_remove();
372 _vstack()->refresh_view(_view, 0, *_view);
374 static_cast<Observer*>(this)->l_remove();