0bac895a28d57d0ce4975574167c3ce832cad083
[bertos.git] / bertos / gui / leveledit.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2004, 2006 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  * \brief Generic editor for (volume/gain/contrast/...) setting.
34  *
35  * \version $Id$
36  * \author Stefano Fedrigo <aleph@develer.com>
37  */
38
39 #include "leveledit.h"
40
41 #include <cfg/cfg_gfx.h>
42 #include <cfg/macros.h> /* MAX() */
43
44 #include <drv/kbd.h>
45 #include <drv/timer.h>
46
47 #include <gui/levelbar.h>
48
49 #include <mware/pgm.h>
50
51 #include <gfx/text.h>
52 #include <gfx/font.h>
53
54 #if CONFIG_MENU_MENUBAR
55 #include <gui/menubar.h>
56 #endif
57
58 // BEGIN project_grl LOCAL
59 #include <drv/lcd_gfx.h>
60 #include <gui/guiman.h>
61 // END project_grl LOCAL
62
63 #warning FIXME: Revise me!
64
65 #define LBAR_HEIGHT 16
66
67 /**
68  * Allow user to change level.
69  */
70 void level_edit(struct LevelEdit *lev)
71 {
72 #if CONFIG_MENU_MENUBAR
73         /* Labels for menubars */
74         enum LabelId ch_labels[] = { LABEL_C1PLUS2, LABEL_CH_1, LABEL_CH_2 };
75         const_iptr_t labels[] =
76         {
77                 (const_iptr_t)LABEL_BACK,
78                 (const_iptr_t)LABEL_MINUS,
79                 (const_iptr_t)LABEL_PLUS,
80                 (const_iptr_t)LABEL_EMPTY
81         };
82         struct MenuBar mb;
83 #endif /* CONFIG_MENU_MENUBAR */
84
85         struct LevelBar bar1, bar2;
86         keymask_t keys, old_rpt_mask;
87         int step, rep_step;
88
89         rep_step = MAX(lev->step, ((lev->max - lev->min) / 200));
90         step = lev->step;
91
92         // Allow keys repetition.
93         old_rpt_mask = kbd_setRepeatMask(K_UP | K_DOWN);
94
95         text_clear(lev->bitmap);
96         //text_style(STYLEF_UNDERLINE, STYLEF_UNDERLINE);
97         text_puts(lev->title, lev->bitmap);
98         //text_style(0, STYLEF_UNDERLINE);
99
100         if (lev->type & LEVELEDIT_DOUBLE)
101         {
102                 int chn = 0;  /* edit both channels */
103
104                 /* Levelbars init */
105                 lbar_init(&bar1, lev->bitmap, LBAR_HORIZONTAL,
106                                 lev->min, lev->max, *lev->ch1_val, 0, 16, lev->bitmap->width / 2 - 1, 23);
107                 lbar_init(&bar2, lev->bitmap, LBAR_HORIZONTAL,
108                                 lev->min, lev->max, *lev->ch2_val, lev->bitmap->width / 2 + 1, 16, lev->bitmap->width, 23);
109
110                 #if CONFIG_MENU_MENUBAR
111                         labels[3] = (const_iptr_t)ch_labels[chn];
112                         mbar_init(&mb, lev->bitmap, labels, countof(labels));
113                         mbar_draw(&mb);
114                 #endif /* CONFIG_MENU_MENUBAR */
115
116                 /* Input loop for double level setting */
117                 for (;;)
118                 {
119                         #if CONFIG_LEVELEDIT_TIMEOUT != 0
120                                 ticks_t idle_timeout = timer_clock();
121                         #endif
122                         do
123                         {
124                                 if (lev->display_hook)
125                                         lev->display_hook(lev);
126                                 else
127                                 {
128                                         text_xprintf(lev->bitmap, 1, 0, TEXT_CENTER | TEXT_FILL, lev->unit);
129                                         PGM_FUNC(text_xprintf)(lev->bitmap, 1, 3, 0, PGM_STR("%d"), *lev->ch1_val);
130                                         PGM_FUNC(text_xprintf)(lev->bitmap, 1, 14, 0, PGM_STR("%d"), *lev->ch2_val);
131
132                                         lbar_setLevel(&bar1, *lev->ch1_val);
133                                         lbar_setLevel(&bar2, *lev->ch2_val);
134                                         lbar_draw(&bar1);
135                                         lbar_draw(&bar2);
136                                 }
137
138                                 #if CONFIG_LEVELEDIT_TIMEOUT != 0
139                                         if (timer_clock() - idle_timeout > ms_to_ticks(CONFIG_LEVELEDIT_TIMEOUT))
140                                         {
141                                                 /* Accept input implicitly */
142                                                 keys = K_OK;
143                                                 break;
144                                         }
145                                 #endif
146                         }
147                         while (!(keys = kbd_peek()));
148
149                         if (keys & K_CANCEL)
150                                 break;
151
152                         if (keys & K_OK)
153                         {
154                                 chn = (chn + 1) % 3;
155
156                                 #if CONFIG_MENU_MENUBAR
157                                         labels[3] = (const_iptr_t)ch_labels[chn];
158                                         mbar_draw(&mb);
159                                 #endif /* CONFIG_MENU_MENUBAR */
160                         }
161
162                         /* Increment step to achieve greater accelerations on larger values */
163                         if (keys & K_REPEAT)
164                                 step = MIN(rep_step, step + 1);
165                         else
166                                 step = lev->step;
167
168                         if (keys & (K_UP | K_DOWN))
169                         {
170                                 if (keys & K_UP)
171                                 {
172                                         /* If changing both channels (chn == 0), don't change
173                                          * level if one of two is at min or max */
174                                         if (chn != 0 ||
175                                                         (*lev->ch1_val + step <= lev->max
176                                                          && *lev->ch2_val + step <= lev->max))
177                                         {
178                                                 /* If chn == 0 change both channels */
179                                                 if (chn != 2)
180                                                 {
181                                                         *lev->ch1_val += step;
182                                                         if (*lev->ch1_val > lev->max)
183                                                                 *lev->ch1_val = lev->max;
184                                                 }
185                                                 if (chn != 1)
186                                                 {
187                                                         *lev->ch2_val += step;
188                                                         if (*lev->ch2_val > lev->max)
189                                                                 *lev->ch2_val = lev->max;
190                                                 }
191                                         }
192                                 }
193                                 else
194                                 {
195                                         if (chn != 0 ||
196                                                         (*lev->ch1_val - step >= lev->min
197                                                          && *lev->ch2_val - step >= lev->min))
198                                         {
199                                                 if (chn != 2)
200                                                 {
201                                                         *lev->ch1_val -= step;
202                                                         if (*lev->ch1_val < lev->min)
203                                                                 *lev->ch1_val = lev->min;
204                                                 }
205                                                 if (chn != 1)
206                                                 {
207                                                         *lev->ch2_val -= step;
208                                                         if (*lev->ch2_val < lev->min)
209                                                                 *lev->ch2_val = lev->min;
210                                                 }
211                                         }
212                                 }
213
214                                 if (lev->set_hook)
215                                         lev->set_hook();
216                         }
217                 } // end for(;;)
218         }
219         else
220         {
221                 const PGM_ATTR char *fmt = lev->unit ? PGM_STR("%d %s") : PGM_STR("%d");
222
223 /*
224                 const int textw = MAX(PGM_FUNC(text_widthf)(lev->bitmap, fmt, lev->max, lev->unit),
225                                 PGM_FUNC(text_widthf)(lev->bitmap, fmt, lev->min, lev->unit));
226
227                 const coord_t barlen = lev->bitmap->width - 6 - textw;
228 */
229                 const coord_t barlen = lev->bitmap->width;
230                 const coord_t barvtop = lev->bitmap->height / 2 - LBAR_HEIGHT/2 + lev->bitmap->font->height;
231                 lbar_init(&bar1, lev->bitmap, LBAR_HORIZONTAL,
232                           lev->min, lev->max, *lev->ch1_val,
233                           0, barvtop, barlen,  barvtop + LBAR_HEIGHT);
234
235                 #if CONFIG_MENU_MENUBAR
236                         mbar_init(&mb, lev->bitmap, labels, countof(labels));
237                         mbar_draw(&mb);
238                 #endif /* CONFIG_MENU_MENUBAR */
239
240                 /* Input loop for single level setting */
241                 for (;;)
242                 {
243                         #if CONFIG_LEVELEDIT_TIMEOUT != 0
244                                 ticks_t idle_timeout = timer_clock();
245                         #endif
246                         do
247                         {
248                                 if (lev->display_hook)
249                                         lev->display_hook(lev);
250                                 else
251                                 {
252                                         if (lev->type != LEVELEDIT_NOBAR)
253                                         {
254                                                 lbar_setLevel(&bar1, *lev->ch1_val);
255                                                 lbar_draw(&bar1);
256                                         }
257                                         PGM_FUNC(text_xyprintf)(lev->bitmap, 0, bar1.y1 - lev->bitmap->font->height,
258                                                 TEXT_CENTER | TEXT_FILL, fmt, *lev->ch1_val, lev->unit);
259                                 }
260
261                                 #if CONFIG_LEVELEDIT_TIMEOUT != 0
262                                         if (timer_clock() - idle_timeout > CONFIG_LEVELEDIT_TIMEOUT)
263                                         {
264                                                 /* Accept input implicitly */
265                                                 keys = K_CANCEL;
266                                                 break;
267                                         }
268                                 #endif
269
270 // BEGIN project_grl LOCAL
271 #if 1
272                                 //FIXME: must to this only when needed
273                                 lcd_blitBitmap(&lcd_bitmap);
274                         }
275                         while (!(keys = GuiMan_KbdPeek()));
276 #else
277                         }
278                         while (!(keys = kbd_peek()));
279 #endif
280 // END project_grl LOCAL
281
282                         if (keys & K_CANCEL)
283                                 break;
284
285                         /* Increment step to achieve greater accelerations on larger values */
286                         if (keys & K_REPEAT)
287                                 step = MIN(rep_step, step + 1);
288                         else
289                                 step = lev->step;
290
291                         if (keys & K_UP)
292                         {
293                                 *lev->ch1_val += step;
294                                 if (*lev->ch1_val > lev->max)
295                                         *lev->ch1_val = lev->max;
296                         }
297
298                         if (keys & K_DOWN)
299                         {
300                                 *lev->ch1_val -= step;
301                                 if (*lev->ch1_val < lev->min)
302                                         *lev->ch1_val = lev->min;
303                         }
304
305                         if (lev->set_hook)
306                                 lev->set_hook();
307                 }
308         }
309
310         kbd_setRepeatMask(old_rpt_mask);
311 }
312
313 /**
314  * LevelEdit structure initialization.
315  * Init data structure and init LevelEdit widgets.
316  */
317 void level_init(struct LevelEdit *lev,
318                 int type,
319                 struct Bitmap *bmp, const char *title, const char *unit,
320                 int min, int max, int step,
321                 int *ch1_val, int *ch2_val,
322                 level_set_callback *set_hook, display_callback *display_hook)
323 {
324         lev->type   = type;
325         lev->bitmap = bmp;
326         lev->title  = title;
327         lev->unit   = unit;
328         lev->min    = min;
329         lev->max    = max;
330         lev->step   = step;
331
332         lev->ch1_val = ch1_val;
333         lev->ch2_val = ch2_val;
334         lev->set_hook     = set_hook;
335         lev->display_hook = display_hook;
336 }