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