]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/scout-gfx/lib/scrollbar.cc
update
[l4.git] / l4 / pkg / scout-gfx / lib / scrollbar.cc
1 /*
2  * (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
3  *     economic rights: Technische Universität Dresden (Germany)
4  *
5  * This file is part of TUD:OS and distributed under the terms of the
6  * GNU General Public License 2.
7  * Please see the COPYING-GPL-2 file for details.
8  */
9 #include <l4/scout-gfx/scrollbar>
10 #include <l4/scout-gfx/factory>
11
12 #include <algorithm>
13
14 #define  SLIDER_RGBA _binary_slider_rgba_start
15 #define UPARROW_RGBA _binary_uparrow_rgba_start
16 #define DNARROW_RGBA _binary_downarrow_rgba_start
17 #define LFARROW_RGBA _binary_leftarrow_rgba_start
18 #define RIARROW_RGBA _binary_rightarrow_rgba_start
19
20 extern unsigned char SLIDER_RGBA[];
21 extern unsigned char UPARROW_RGBA[];
22 extern unsigned char DNARROW_RGBA[];
23 extern unsigned char LFARROW_RGBA[];
24 extern unsigned char RIARROW_RGBA[];
25
26 namespace Scout_gfx {
27
28 /**
29  * Event handler interface
30  */
31 bool
32 Scrollbar::Arrow_event_handler::handle(Event const &ev)
33 {
34   /* start movement with zero speed */
35   if ((ev.type == Event::PRESS) && (ev.key_cnt == 1))
36     {
37       /* press icon (slight vertical shift, darker shadow) */
38       _icon->rgba(_rgba, Area(32, 32), 1, 3);
39       _icon->refresh();
40
41       _curr_speed = _direction*256;
42       _dst_speed  = _direction*Max_speed;
43       _accel      = 16;
44       _view_pos   = _sb->view_pos() << 8;
45       schedule(10);
46     }
47
48   if ((ev.type == Event::RELEASE) && (ev.key_cnt == 0))
49     {
50       /* release icon */
51       _icon->rgba(_rgba, Area(32, 32));
52       _icon->refresh();
53
54       _accel     = 64;
55       _dst_speed = 0;
56     }
57
58   return true;
59 }
60
61 /**
62  * Tick interface
63  */
64 int
65 Scrollbar::Arrow_event_handler::on_tick()
66 {
67   using std::min;
68   using std::max;
69
70   /* accelerate */
71   if (_curr_speed < _dst_speed)
72     _curr_speed = min(_curr_speed + _accel, _dst_speed);
73
74   /* decelerate */
75   if (_curr_speed > _dst_speed)
76     _curr_speed = max(_curr_speed - _accel, _dst_speed);
77
78   /* soft stopping on boundaries */
79   while ((_curr_speed < 0) && (_view_pos > 0)
80       && (_curr_speed*_curr_speed > _view_pos*_accel*4))
81     _curr_speed = min(0, _curr_speed + _accel*4);
82
83   int max_pos;
84   while ((_curr_speed > 0)
85       && ((max_pos = (_sb->real_size() - _sb->view_size())*256 - _view_pos) > 0)
86       && (_curr_speed*_curr_speed > max_pos*_accel*4))
87     _curr_speed = max(0, _curr_speed - _accel*4);
88
89   /* move view position with current speed */
90   _view_pos = max(0, _view_pos + _curr_speed);
91
92   /* set new view position */
93   int old_view_pos = _sb->view_pos();
94   _sb->view(_sb->real_size(), _sb->view_size(), _view_pos>>8);
95   if (old_view_pos != _sb->view_pos())
96     _sb->notify_listener();
97
98   /* keep ticking as long as we are on speed */
99   return (_curr_speed != 0);
100 }
101
102
103 /**
104  * Event handler interface
105  */
106 bool
107 Scrollbar::Slider_event_handler::handle(Event const &ev)
108 {
109
110   int p = _sb->orientation() == Vertical ? ev.m.y() : ev.m.x();
111   /* start movement with zero speed */
112   if ((ev.type == Event::PRESS) && (ev.key_cnt == 1))
113     {
114       /* press icon (slight vertical shift, darker shadow) */
115       _icon->rgba(_rgba, Area(32,32), 1, 3);
116       _icon->refresh();
117
118       _om = p;
119       _cm = p;
120       _op = _sb->slider_pos();
121     }
122
123   if ((ev.type == Event::RELEASE) && (ev.key_cnt == 0))
124     {
125       /* release icon */
126       _icon->rgba(_rgba, Area(32, 32));
127       _icon->refresh();
128     }
129
130   if (ev.key_cnt && (p != _cm))
131     {
132       _cm = p;
133       _sb->slider_pos(_op + _cm - _om);
134       _sb->notify_listener();
135     }
136
137   return true;
138 }
139
140
141
142 /*************************
143  ** Scrollbar interface **
144  *************************/
145
146 Scrollbar::Scrollbar(Factory *f, Orientation o)
147 : _uparrow(f->create_icon(o == Vertical ? UPARROW_RGBA : LFARROW_RGBA, Area(32, 32))),
148   _dnarrow(f->create_icon(o == Vertical ? DNARROW_RGBA : RIARROW_RGBA, Area(32, 32))),
149   _slider(f->create_icon(SLIDER_RGBA, Area(32, 32))),
150   _orientation(o),
151   _uph(this, _uparrow, -1, o == Vertical ? UPARROW_RGBA : LFARROW_RGBA),
152   _dnh(this, _dnarrow,  1, o == Vertical ? DNARROW_RGBA : RIARROW_RGBA),
153   _slh(this, _slider, SLIDER_RGBA)
154
155 {
156   /* init scrollbar elements */
157   _uparrow->alpha(0);
158   _dnarrow->alpha(0);
159   _slider->alpha(0);
160
161   append(_uparrow);
162   append(_dnarrow);
163   append(_slider);
164
165   /* define event handlers for scrollbar elements */
166   _uparrow->event_handler(&_uph);
167   _dnarrow->event_handler(&_dnh);
168   _slider->event_handler(&_slh);
169
170   if (o == Vertical)
171     _size = Area(Sb_elem_w, Sb_elem_h*3);
172   else
173     _size = Area(Sb_elem_w * 3, Sb_elem_h);
174
175   _real_size  = 100;
176   _view_size  = 100;
177   _view_pos   = 0;
178   _listener   = 0;
179   _visibility = 0;
180 }
181
182 void
183 Scrollbar::refresh_slider_geometry()
184 {
185   if (_orientation == Vertical)
186     _slider->set_geometry(Rect(Point(0, slider_pos()), Area(Sb_elem_w, slider_size())));
187   else
188     _slider->set_geometry(Rect(Point(slider_pos(), 0), Area(slider_size(), Sb_elem_h)));
189 }
190
191 void
192 Scrollbar::slider_pos(int pos)
193 {
194   int slider_bg_h;
195   int n;
196   if (_orientation == Vertical)
197     {
198       n = Sb_elem_h;
199       slider_bg_h = _size.h() - Sb_elem_h*2;
200     }
201   else
202     {
203       n = Sb_elem_w;
204       slider_bg_h = _size.w() - Sb_elem_w*2;
205     }
206
207   _view_pos = ((pos - n)*_real_size)/slider_bg_h;
208   _view_pos = std::max(0, std::min(_view_pos,  _real_size - _view_size));
209
210   refresh_slider_geometry();
211
212 }
213
214
215
216 /***********************
217  ** Element interface **
218  ***********************/
219
220 Area
221 Scrollbar::min_size() const
222 {
223   Area us = _uparrow->preferred_size();
224   Area ss = _slider->preferred_size();
225   Area ds = _dnarrow->preferred_size();
226   int a = Sb_elem_w * (_orientation == Horizontal ? 4 : 1);
227   int b = Sb_elem_h * (_orientation == Vertical ? 4 : 1);
228   return Area(a, b);
229 }
230
231 Area
232 Scrollbar::preferred_size() const
233 { return Scrollbar::min_size(); }
234
235 Area
236 Scrollbar::max_size() const
237 {
238   if (_orientation == Vertical)
239     return Area(preferred_size().w(), Area::Max_h);
240   else
241     return Area(Area::Max_w, preferred_size().h());
242 }
243
244 void
245 Scrollbar::set_geometry(Rect const &r)
246 {
247   Area s = r.area();
248   s = s.min(max_size()).max(min_size());
249   _pos = r.p1();
250   _size = s;
251
252   if (_orientation == Vertical)
253     _dnarrow->set_geometry(Rect(Point(0, s.h() - Sb_elem_h), _dnarrow->size()));
254   else
255     _dnarrow->set_geometry(Rect(Point(s.w() - Sb_elem_w, 0), _dnarrow->size()));
256
257   refresh_slider_geometry();
258 }
259
260 void
261 Scrollbar::visibility(bool new_visibility)
262 {
263   if (_visibility ^ new_visibility)
264     {
265       enum { Default_alpha = 100 };
266       int alpha = new_visibility ? Default_alpha : 0;
267       int speed = new_visibility ? 3 : 2;
268       dynamic_cast<Fader*>(_uparrow)->fade_to(alpha, speed);
269       dynamic_cast<Fader*>(_dnarrow)->fade_to(alpha, speed);
270       dynamic_cast<Fader*>(_slider)->fade_to(alpha, speed);
271     }
272
273   _visibility = new_visibility;
274 }
275
276
277 }