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