/** * \file * * * \brief Generic editor for (volume/gain/contrast/...) setting. * * \author Stefano Fedrigo */ #include "leveledit.h" #include "cfg/cfg_menu.h" #include /* MAX() */ #include #include #include #include #include #include #if CONFIG_MENU_MENUBAR #include #endif #warning FIXME: Revise me! #define LBAR_HEIGHT 16 /** * Allow user to change level. */ void level_edit(struct LevelEdit *lev) { #if CONFIG_MENU_MENUBAR /* Labels for menubars */ enum LabelId ch_labels[] = { LABEL_C1PLUS2, LABEL_CH_1, LABEL_CH_2 }; const_iptr_t labels[] = { (const_iptr_t)LABEL_BACK, (const_iptr_t)LABEL_MINUS, (const_iptr_t)LABEL_PLUS, (const_iptr_t)LABEL_EMPTY }; struct MenuBar mb; #endif /* CONFIG_MENU_MENUBAR */ struct LevelBar bar1, bar2; keymask_t keys, old_rpt_mask; int step, rep_step; rep_step = MAX(lev->step, ((lev->max - lev->min) / 200)); step = lev->step; // Allow keys repetition. old_rpt_mask = kbd_setRepeatMask(K_UP | K_DOWN); text_clear(lev->bitmap); //text_style(STYLEF_UNDERLINE, STYLEF_UNDERLINE); text_puts(lev->title, lev->bitmap); //text_style(0, STYLEF_UNDERLINE); if (lev->type & LEVELEDIT_DOUBLE) { int chn = 0; /* edit both channels */ /* Levelbars init */ lbar_init(&bar1, lev->bitmap, LBAR_HORIZONTAL, lev->min, lev->max, *lev->ch1_val, 0, 16, lev->bitmap->width / 2 - 1, 23); lbar_init(&bar2, lev->bitmap, LBAR_HORIZONTAL, lev->min, lev->max, *lev->ch2_val, lev->bitmap->width / 2 + 1, 16, lev->bitmap->width, 23); #if CONFIG_MENU_MENUBAR labels[3] = (const_iptr_t)ch_labels[chn]; mbar_init(&mb, lev->bitmap, labels, countof(labels)); mbar_draw(&mb); #endif /* CONFIG_MENU_MENUBAR */ /* Input loop for double level setting */ for (;;) { #if CONFIG_LEVELEDIT_TIMEOUT != 0 ticks_t idle_timeout = timer_clock(); #endif do { if (lev->display_hook) lev->display_hook(lev); else { text_xprintf(lev->bitmap, 1, 0, TEXT_CENTER | TEXT_FILL, lev->unit); PGM_FUNC(text_xprintf)(lev->bitmap, 1, 3, 0, PGM_STR("%d"), *lev->ch1_val); PGM_FUNC(text_xprintf)(lev->bitmap, 1, 14, 0, PGM_STR("%d"), *lev->ch2_val); lbar_setLevel(&bar1, *lev->ch1_val); lbar_setLevel(&bar2, *lev->ch2_val); lbar_draw(&bar1); lbar_draw(&bar2); } #if CONFIG_LEVELEDIT_TIMEOUT != 0 if (timer_clock() - idle_timeout > ms_to_ticks(CONFIG_LEVELEDIT_TIMEOUT)) { /* Accept input implicitly */ keys = K_OK; break; } #endif } while (!(keys = kbd_peek())); if (keys & K_CANCEL) break; if (keys & K_OK) { chn = (chn + 1) % 3; #if CONFIG_MENU_MENUBAR labels[3] = (const_iptr_t)ch_labels[chn]; mbar_draw(&mb); #endif /* CONFIG_MENU_MENUBAR */ } /* Increment step to achieve greater accelerations on larger values */ if (keys & K_REPEAT) step = MIN(rep_step, step + 1); else step = lev->step; if (keys & (K_UP | K_DOWN)) { if (keys & K_UP) { /* If changing both channels (chn == 0), don't change * level if one of two is at min or max */ if (chn != 0 || (*lev->ch1_val + step <= lev->max && *lev->ch2_val + step <= lev->max)) { /* If chn == 0 change both channels */ if (chn != 2) { *lev->ch1_val += step; if (*lev->ch1_val > lev->max) *lev->ch1_val = lev->max; } if (chn != 1) { *lev->ch2_val += step; if (*lev->ch2_val > lev->max) *lev->ch2_val = lev->max; } } } else { if (chn != 0 || (*lev->ch1_val - step >= lev->min && *lev->ch2_val - step >= lev->min)) { if (chn != 2) { *lev->ch1_val -= step; if (*lev->ch1_val < lev->min) *lev->ch1_val = lev->min; } if (chn != 1) { *lev->ch2_val -= step; if (*lev->ch2_val < lev->min) *lev->ch2_val = lev->min; } } } if (lev->set_hook) lev->set_hook(); } } // end for(;;) } else { const PGM_ATTR char *fmt = lev->unit ? PGM_STR("%d %s") : PGM_STR("%d"); /* const int textw = MAX(PGM_FUNC(text_widthf)(lev->bitmap, fmt, lev->max, lev->unit), PGM_FUNC(text_widthf)(lev->bitmap, fmt, lev->min, lev->unit)); const coord_t barlen = lev->bitmap->width - 6 - textw; */ const coord_t barlen = lev->bitmap->width; const coord_t barvtop = lev->bitmap->height / 2 - LBAR_HEIGHT/2 + lev->bitmap->font->height; lbar_init(&bar1, lev->bitmap, LBAR_HORIZONTAL, lev->min, lev->max, *lev->ch1_val, 0, barvtop, barlen, barvtop + LBAR_HEIGHT); #if CONFIG_MENU_MENUBAR mbar_init(&mb, lev->bitmap, labels, countof(labels)); mbar_draw(&mb); #endif /* CONFIG_MENU_MENUBAR */ /* Input loop for single level setting */ for (;;) { #if CONFIG_LEVELEDIT_TIMEOUT != 0 ticks_t idle_timeout = timer_clock(); #endif do { if (lev->display_hook) lev->display_hook(lev); else { if (lev->type != LEVELEDIT_NOBAR) { lbar_setLevel(&bar1, *lev->ch1_val); lbar_draw(&bar1); } PGM_FUNC(text_xyprintf)(lev->bitmap, 0, bar1.y1 - lev->bitmap->font->height, TEXT_CENTER | TEXT_FILL, fmt, *lev->ch1_val, lev->unit); } #if CONFIG_LEVELEDIT_TIMEOUT != 0 if (timer_clock() - idle_timeout > CONFIG_LEVELEDIT_TIMEOUT) { /* Accept input implicitly */ keys = K_CANCEL; break; } #endif } while (!(keys = kbd_peek())); if (keys & K_CANCEL) break; /* Increment step to achieve greater accelerations on larger values */ if (keys & K_REPEAT) step = MIN(rep_step, step + 1); else step = lev->step; if (keys & K_UP) { *lev->ch1_val += step; if (*lev->ch1_val > lev->max) *lev->ch1_val = lev->max; } if (keys & K_DOWN) { *lev->ch1_val -= step; if (*lev->ch1_val < lev->min) *lev->ch1_val = lev->min; } if (lev->set_hook) lev->set_hook(); } } kbd_setRepeatMask(old_rpt_mask); } /** * LevelEdit structure initialization. * Init data structure and init LevelEdit widgets. */ void level_init(struct LevelEdit *lev, int type, struct Bitmap *bmp, const char *title, const char *unit, int min, int max, int step, int *ch1_val, int *ch2_val, level_set_callback *set_hook, display_callback *display_hook) { lev->type = type; lev->bitmap = bmp; lev->title = title; lev->unit = unit; lev->min = min; lev->max = max; lev->step = step; lev->ch1_val = ch1_val; lev->ch2_val = ch2_val; lev->set_hook = set_hook; lev->display_hook = display_hook; }