Revert last commit.
[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  * \author Stefano Fedrigo <aleph@develer.com>
36  */
37
38 #include "leveledit.h"
39
40 #include "cfg/cfg_gfx.h"
41 #include <cfg/macros.h> /* MAX() */
42
43 #include <drv/kbd.h>
44 #include <drv/timer.h>
45
46 #include <gui/levelbar.h>
47
48 #include <cpu/pgm.h>
49
50 #include <gfx/text.h>
51 #include <gfx/font.h>
52
53 #if CONFIG_MENU_MENUBAR
54 #include <gui/menubar.h>
55 #endif
56
57 #include <drv/lcd_gfx.h>
58
59 #warning FIXME: Revise me!
60
61 #define LBAR_HEIGHT 16
62
63 /**
64  * Allow user to change level.
65  */
66 void level_edit(struct LevelEdit *lev)
67 {
68 #if CONFIG_MENU_MENUBAR
69         /* Labels for menubars */
70         enum LabelId ch_labels[] = { LABEL_C1PLUS2, LABEL_CH_1, LABEL_CH_2 };
71         const_iptr_t labels[] =
72         {
73                 (const_iptr_t)LABEL_BACK,
74                 (const_iptr_t)LABEL_MINUS,
75                 (const_iptr_t)LABEL_PLUS,
76                 (const_iptr_t)LABEL_EMPTY
77         };
78         struct MenuBar mb;
79 #endif /* CONFIG_MENU_MENUBAR */
80
81         struct LevelBar bar1, bar2;
82         keymask_t keys, old_rpt_mask;
83         int step, rep_step;
84
85         rep_step = MAX(lev->step, ((lev->max - lev->min) / 200));
86         step = lev->step;
87
88         // Allow keys repetition.
89         old_rpt_mask = kbd_setRepeatMask(K_UP | K_DOWN);
90
91         text_clear(lev->bitmap);
92         //text_style(STYLEF_UNDERLINE, STYLEF_UNDERLINE);
93         text_puts(lev->title, lev->bitmap);
94         //text_style(0, STYLEF_UNDERLINE);
95
96         if (lev->type & LEVELEDIT_DOUBLE)
97         {
98                 int chn = 0;  /* edit both channels */
99
100                 /* Levelbars init */
101                 lbar_init(&bar1, lev->bitmap, LBAR_HORIZONTAL,
102                                 lev->min, lev->max, *lev->ch1_val, 0, 16, lev->bitmap->width / 2 - 1, 23);
103                 lbar_init(&bar2, lev->bitmap, LBAR_HORIZONTAL,
104                                 lev->min, lev->max, *lev->ch2_val, lev->bitmap->width / 2 + 1, 16, lev->bitmap->width, 23);
105
106                 #if CONFIG_MENU_MENUBAR
107                         labels[3] = (const_iptr_t)ch_labels[chn];
108                         mbar_init(&mb, lev->bitmap, labels, countof(labels));
109                         mbar_draw(&mb);
110                 #endif /* CONFIG_MENU_MENUBAR */
111
112                 /* Input loop for double level setting */
113                 for (;;)
114                 {
115                         #if CONFIG_LEVELEDIT_TIMEOUT != 0
116                                 ticks_t idle_timeout = timer_clock();
117                         #endif
118                         do
119                         {
120                                 if (lev->display_hook)
121                                         lev->display_hook(lev);
122                                 else
123                                 {
124                                         text_xprintf(lev->bitmap, 1, 0, TEXT_CENTER | TEXT_FILL, lev->unit);
125                                         PGM_FUNC(text_xprintf)(lev->bitmap, 1, 3, 0, PGM_STR("%d"), *lev->ch1_val);
126                                         PGM_FUNC(text_xprintf)(lev->bitmap, 1, 14, 0, PGM_STR("%d"), *lev->ch2_val);
127
128                                         lbar_setLevel(&bar1, *lev->ch1_val);
129                                         lbar_setLevel(&bar2, *lev->ch2_val);
130                                         lbar_draw(&bar1);
131                                         lbar_draw(&bar2);
132                                 }
133
134                                 #if CONFIG_LEVELEDIT_TIMEOUT != 0
135                                         if (timer_clock() - idle_timeout > ms_to_ticks(CONFIG_LEVELEDIT_TIMEOUT))
136                                         {
137                                                 /* Accept input implicitly */
138                                                 keys = K_OK;
139                                                 break;
140                                         }
141                                 #endif
142                         }
143                         while (!(keys = kbd_peek()));
144
145                         if (keys & K_CANCEL)
146                                 break;
147
148                         if (keys & K_OK)
149                         {
150                                 chn = (chn + 1) % 3;
151
152                                 #if CONFIG_MENU_MENUBAR
153                                         labels[3] = (const_iptr_t)ch_labels[chn];
154                                         mbar_draw(&mb);
155                                 #endif /* CONFIG_MENU_MENUBAR */
156                         }
157
158                         /* Increment step to achieve greater accelerations on larger values */
159                         if (keys & K_REPEAT)
160                                 step = MIN(rep_step, step + 1);
161                         else
162                                 step = lev->step;
163
164                         if (keys & (K_UP | K_DOWN))
165                         {
166                                 if (keys & K_UP)
167                                 {
168                                         /* If changing both channels (chn == 0), don't change
169                                          * level if one of two is at min or max */
170                                         if (chn != 0 ||
171                                                         (*lev->ch1_val + step <= lev->max
172                                                          && *lev->ch2_val + step <= lev->max))
173                                         {
174                                                 /* If chn == 0 change both channels */
175                                                 if (chn != 2)
176                                                 {
177                                                         *lev->ch1_val += step;
178                                                         if (*lev->ch1_val > lev->max)
179                                                                 *lev->ch1_val = lev->max;
180                                                 }
181                                                 if (chn != 1)
182                                                 {
183                                                         *lev->ch2_val += step;
184                                                         if (*lev->ch2_val > lev->max)
185                                                                 *lev->ch2_val = lev->max;
186                                                 }
187                                         }
188                                 }
189                                 else
190                                 {
191                                         if (chn != 0 ||
192                                                         (*lev->ch1_val - step >= lev->min
193                                                          && *lev->ch2_val - step >= lev->min))
194                                         {
195                                                 if (chn != 2)
196                                                 {
197                                                         *lev->ch1_val -= step;
198                                                         if (*lev->ch1_val < lev->min)
199                                                                 *lev->ch1_val = lev->min;
200                                                 }
201                                                 if (chn != 1)
202                                                 {
203                                                         *lev->ch2_val -= step;
204                                                         if (*lev->ch2_val < lev->min)
205                                                                 *lev->ch2_val = lev->min;
206                                                 }
207                                         }
208                                 }
209
210                                 if (lev->set_hook)
211                                         lev->set_hook();
212                         }
213                 } // end for(;;)
214         }
215         else
216         {
217                 const PGM_ATTR char *fmt = lev->unit ? PGM_STR("%d %s") : PGM_STR("%d");
218
219 /*
220                 const int textw = MAX(PGM_FUNC(text_widthf)(lev->bitmap, fmt, lev->max, lev->unit),
221                                 PGM_FUNC(text_widthf)(lev->bitmap, fmt, lev->min, lev->unit));
222
223                 const coord_t barlen = lev->bitmap->width - 6 - textw;
224 */
225                 const coord_t barlen = lev->bitmap->width;
226                 const coord_t barvtop = lev->bitmap->height / 2 - LBAR_HEIGHT/2 + lev->bitmap->font->height;
227                 lbar_init(&bar1, lev->bitmap, LBAR_HORIZONTAL,
228                           lev->min, lev->max, *lev->ch1_val,
229                           0, barvtop, barlen,  barvtop + LBAR_HEIGHT);
230
231                 #if CONFIG_MENU_MENUBAR
232                         mbar_init(&mb, lev->bitmap, labels, countof(labels));
233                         mbar_draw(&mb);
234                 #endif /* CONFIG_MENU_MENUBAR */
235
236                 /* Input loop for single level setting */
237                 for (;;)
238                 {
239                         #if CONFIG_LEVELEDIT_TIMEOUT != 0
240                                 ticks_t idle_timeout = timer_clock();
241                         #endif
242                         do
243                         {
244                                 if (lev->display_hook)
245                                         lev->display_hook(lev);
246                                 else
247                                 {
248                                         if (lev->type != LEVELEDIT_NOBAR)
249                                         {
250                                                 lbar_setLevel(&bar1, *lev->ch1_val);
251                                                 lbar_draw(&bar1);
252                                         }
253                                         PGM_FUNC(text_xyprintf)(lev->bitmap, 0, bar1.y1 - lev->bitmap->font->height,
254                                                 TEXT_CENTER | TEXT_FILL, fmt, *lev->ch1_val, lev->unit);
255                                 }
256
257                                 #if CONFIG_LEVELEDIT_TIMEOUT != 0
258                                         if (timer_clock() - idle_timeout > CONFIG_LEVELEDIT_TIMEOUT)
259                                         {
260                                                 /* Accept input implicitly */
261                                                 keys = K_CANCEL;
262                                                 break;
263                                         }
264                                 #endif
265
266                         }
267                         while (!(keys = kbd_peek()));
268
269                         if (keys & K_CANCEL)
270                                 break;
271
272                         /* Increment step to achieve greater accelerations on larger values */
273                         if (keys & K_REPEAT)
274                                 step = MIN(rep_step, step + 1);
275                         else
276                                 step = lev->step;
277
278                         if (keys & K_UP)
279                         {
280                                 *lev->ch1_val += step;
281                                 if (*lev->ch1_val > lev->max)
282                                         *lev->ch1_val = lev->max;
283                         }
284
285                         if (keys & K_DOWN)
286                         {
287                                 *lev->ch1_val -= step;
288                                 if (*lev->ch1_val < lev->min)
289                                         *lev->ch1_val = lev->min;
290                         }
291
292                         if (lev->set_hook)
293                                 lev->set_hook();
294                 }
295         }
296
297         kbd_setRepeatMask(old_rpt_mask);
298 }
299
300 /**
301  * LevelEdit structure initialization.
302  * Init data structure and init LevelEdit widgets.
303  */
304 void level_init(struct LevelEdit *lev,
305                 int type,
306                 struct Bitmap *bmp, const char *title, const char *unit,
307                 int min, int max, int step,
308                 int *ch1_val, int *ch2_val,
309                 level_set_callback *set_hook, display_callback *display_hook)
310 {
311         lev->type   = type;
312         lev->bitmap = bmp;
313         lev->title  = title;
314         lev->unit   = unit;
315         lev->min    = min;
316         lev->max    = max;
317         lev->step   = step;
318
319         lev->ch1_val = ch1_val;
320         lev->ch2_val = ch2_val;
321         lev->set_hook     = set_hook;
322         lev->display_hook = display_hook;
323 }