Beispiel #1
0
/* Draw's all the EQ sliders. Returns the total height of the sliders drawn */
static void draw_eq_sliders(struct screen * screen, int x, int y,
                            int nb_eq_sliders, int start_item,
                            int current_band, enum eq_slider_mode mode)
{
    int height = y;

    start_item = MIN(start_item, EQ_NUM_BANDS - nb_eq_sliders);

    for (int i = 0; i < EQ_NUM_BANDS; i++) {
        struct eq_band_setting *setting = &global_settings.eq_band_settings[i];
        int cutoff = setting->cutoff;
        int q      = setting->q;
        int gain   = setting->gain;

        if (i == start_item + nb_eq_sliders)
            break;

        if (i >= start_item) {
            height += draw_eq_slider(screen, x, height, screen->lcdwidth - x - 1,
                                     cutoff, q, gain, i == current_band, mode,
                                     i);
            /* add a margin */
            height++;
        }
    }

    if (nb_eq_sliders != EQ_NUM_BANDS)
        gui_scrollbar_draw(screen, 0, y, SCROLLBAR_SIZE - 1,
                           screen->lcdheight - y, EQ_NUM_BANDS,
                           start_item, start_item + nb_eq_sliders,
                           VERTICAL);
    return;
}
Beispiel #2
0
void show_busy_slider(struct screen *s, int x, int y, int width, int height)
{
    static int start = 0, dir = 1;
    gui_scrollbar_draw(s, x, y, width, height, 100,
                           start, start+20, HORIZONTAL);
#if NB_SCREENS > 1
    if (s->screen_type == SCREEN_MAIN)
#endif
    {
        start += (dir*2);
        if (start > 79)
            dir = -1;
        else if (start < 1)
            dir = 1;
    }
}
Beispiel #3
0
void list_draw(struct screen *display, struct gui_synclist *list)
{
    struct viewport list_icons;
    int start, end, line_height, style, i;
    const int screen = display->screen_type;
    const int list_start_item = list->start_item[screen];
    const int icon_width = get_icon_width(screen) + ICON_PADDING;
    const bool scrollbar_in_left = (global_settings.scrollbar == SCROLLBAR_LEFT);
    const bool show_cursor = !global_settings.cursor_style &&
                        list->show_selection_marker;
    struct viewport *parent = (list->parent[screen]);
#ifdef HAVE_LCD_COLOR
    unsigned char cur_line = 0;
#endif
    int item_offset;
    bool show_title;
    struct viewport *list_text_vp = &list_text[screen];

    line_height = font_get(parent->font)->height;
    display->set_viewport(parent);
    display->clear_viewport();
    display->scroll_stop(list_text_vp);
    *list_text_vp = *parent;
    if ((show_title = draw_title(display, list)))
    {
        list_text_vp->y += line_height;
        list_text_vp->height -= line_height;
    }

    const int nb_lines = viewport_get_nb_lines(list_text_vp);

    start = list_start_item;
    end = start + nb_lines;

#ifdef HAVE_TOUCHSCREEN
    if (list->selected_item == 0 || (list->nb_items < nb_lines))
        y_offset = 0; /* reset in case it's a new list */

    int draw_offset = y_offset;
    /* draw some extra items to not have empty lines at the top and bottom */
    if (y_offset > 0)
    {
        /* make it negative for more consistent apparence when switching
         * directions */
        draw_offset -= line_height;
        if (start > 0)
            start--;
    }
    else if (y_offset < 0)
        end++;
#else
    #define draw_offset 0
#endif

    /* draw the scrollbar if its needed */
    if (global_settings.scrollbar && nb_lines < list->nb_items)
    {
        struct viewport vp = *list_text_vp;
        vp.width = SCROLLBAR_WIDTH;
        vp.height = line_height * nb_lines;
        vp.x = parent->x;
        list_text_vp->width -= SCROLLBAR_WIDTH;
        if (scrollbar_in_left)
            list_text_vp->x += SCROLLBAR_WIDTH;
        else
            vp.x += list_text_vp->width;
        display->set_viewport(&vp);
        gui_scrollbar_draw(display,
                (scrollbar_in_left? 0: 1), 0, SCROLLBAR_WIDTH-1, vp.height,
                list->nb_items, list_start_item, list_start_item + nb_lines,
                VERTICAL);
    }
    else if (show_title)
    {
        /* shift everything a bit in relation to the title... */
        if (!VP_IS_RTL(list_text_vp) && scrollbar_in_left)
        {
            list_text_vp->width -= SCROLLBAR_WIDTH;
            list_text_vp->x += SCROLLBAR_WIDTH;
        }
        else if (VP_IS_RTL(list_text_vp) && !scrollbar_in_left)
        {
            list_text_vp->width -= SCROLLBAR_WIDTH;
        }
    }

    /* setup icon placement */
    list_icons = *list_text_vp;
    int icon_count = (list->callback_get_item_icon != NULL) ? 1 : 0;
    if (show_cursor)
        icon_count++;
    if (icon_count)
    {
        list_icons.width = icon_width * icon_count;
        list_text_vp->width -= list_icons.width + ICON_PADDING;
        if (VP_IS_RTL(&list_icons))
            list_icons.x += list_text_vp->width + ICON_PADDING;
        else
            list_text_vp->x += list_icons.width + ICON_PADDING;
    }

    for (i=start; i<end && i<list->nb_items; i++)
    {
        /* do the text */
        unsigned const char *s;
        char entry_buffer[MAX_PATH];
        unsigned char *entry_name;
        int text_pos = 0;
        int line = i - start;
        s = list->callback_get_item_name(i, list->data, entry_buffer,
                                         sizeof(entry_buffer));
        entry_name = P2STR(s);
        display->set_viewport(list_text_vp);
        style = STYLE_DEFAULT;
        /* position the string at the correct offset place */
        int item_width,h;
        display->getstringsize(entry_name, &item_width, &h);
        item_offset = gui_list_get_item_offset(list, item_width, text_pos,
                display, list_text_vp);

#ifdef HAVE_LCD_COLOR
        /* if the list has a color callback */
        if (list->callback_get_item_color)
        {
            int color = list->callback_get_item_color(i, list->data);
            /* if color selected */
            if (color >= 0)
            {
                style |= STYLE_COLORED|color;
            }
        }
#endif
        /* draw the selected line */
        if(
#ifdef HAVE_TOUCHSCREEN
            /* don't draw it during scrolling */
            scroll_mode == SCROLL_NONE &&
#endif
                i >= list->selected_item
                && i <  list->selected_item + list->selected_size
                && list->show_selection_marker)
        {/* The selected item must be displayed scrolling */
            if (global_settings.cursor_style == 1
#ifdef HAVE_REMOTE_LCD
                    /* the global_settings.cursor_style check is here to make
                    * sure if they want the cursor instead of bar it will work
                    */
                    || (display->depth < 16 && global_settings.cursor_style)
#endif
            )
            {
                /* Display inverted-line-style */
                style = STYLE_INVERT;
            }
#ifdef HAVE_LCD_COLOR
            else if (global_settings.cursor_style == 2)
            {
                /* Display colour line selector */
                style = STYLE_COLORBAR;
            }
            else if (global_settings.cursor_style == 3)
            {
                /* Display gradient line selector */
                style = STYLE_GRADIENT;

                /* Make the lcd driver know how many lines the gradient should
                   cover and current line number */
                /* number of selected lines */
                style |= NUMLN_PACK(list->selected_size);
                /* current line number, zero based */
                style |= CURLN_PACK(cur_line);
                cur_line++;
            }
#endif
            /* if the text is smaller than the viewport size */
            if (item_offset> item_width - (list_text_vp->width - text_pos))
            {
                /* don't scroll */
                display->puts_style_xyoffset(0, line, entry_name,
                        style, item_offset, draw_offset);
            }
            else
            {
                display->puts_scroll_style_xyoffset(0, line, entry_name,
                        style, item_offset, draw_offset);
            }
        }
        else
        {
            if (list->scroll_all)
                display->puts_scroll_style_xyoffset(0, line, entry_name,
                        style, item_offset, draw_offset);
            else
                display->puts_style_xyoffset(0, line, entry_name,
                        style, item_offset, draw_offset);
        }
        /* do the icon */
        display->set_viewport(&list_icons);
        if (list->callback_get_item_icon != NULL)
        {
            screen_put_icon_with_offset(display, show_cursor?1:0,
                                    (line),show_cursor?ICON_PADDING:0,draw_offset,
                                    list->callback_get_item_icon(i, list->data));
        }
        if (show_cursor && i >= list->selected_item &&
                i <  list->selected_item + list->selected_size)
        {
            screen_put_icon_with_offset(display, 0, line, 0, draw_offset, Icon_Cursor);
        }
    }
    display->set_viewport(parent);
    display->update_viewport();
    display->set_viewport(NULL);
}
Beispiel #4
0
/* Draw the UI for a whole EQ band */
static int draw_eq_slider(struct screen * screen, int x, int y,
    int width, int cutoff, int q, int gain, bool selected,
    enum eq_slider_mode mode, int band)
{
    char buf[26];
    int steps, min_item, max_item;
    int abs_gain = abs(gain);
    int x1, x2, y1, total_height;
    int w, h;

    switch(mode) {
    case Q:
        steps = EQ_Q_MAX - EQ_Q_MIN;
        min_item = q - EQ_Q_STEP - EQ_Q_MIN;
        max_item = q + EQ_Q_STEP - EQ_Q_MIN;
        break;
    case CUTOFF:
        steps = EQ_CUTOFF_MAX - EQ_CUTOFF_MIN;
        min_item = cutoff - EQ_CUTOFF_FAST_STEP * 2;
        max_item = cutoff + EQ_CUTOFF_FAST_STEP * 2;
        break;
    case GAIN:
    default:
        steps = EQ_GAIN_MAX - EQ_GAIN_MIN;
        min_item = abs(EQ_GAIN_MIN) + gain - EQ_GAIN_STEP * 5;
        max_item = abs(EQ_GAIN_MIN) + gain + EQ_GAIN_STEP * 5;
        break;
    }

    /* Start two pixels in, one for border, one for margin */
    x1 = x + 2;
    y1 = y + 2;

    /* Print out the band label */
    if (band == 0) {
        screen->putsxy(x1, y1, "LS: ");
        screen->getstringsize("LS:", &w, &h);
    } else if (band == EQ_NUM_BANDS - 1) {
        screen->putsxy(x1, y1, "HS: ");
        screen->getstringsize("HS:", &w, &h);
    } else {
        snprintf(buf, sizeof(buf),  "PK%d:", band);
        screen->putsxy(x1, y1, buf);
        screen->getstringsize(buf, &w, &h);
    }

    screen->getstringsize("A", &w, &h);
    x1 += 5*w; /* 4 chars for label + 1 space = 5 */

    /* Print out gain part of status line (left justify after label) */
    if (mode == GAIN && selected)
        screen->set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID);
    else
        screen->set_drawmode(DRMODE_SOLID);

    snprintf(buf, sizeof(buf), "%s%2d.%d%s", gain < 0 ? "-" : " ",
        abs_gain / EQ_USER_DIVISOR, abs_gain % EQ_USER_DIVISOR,
        screen->lcdwidth >= 160 ? "dB" : "");
    screen->putsxy(x1, y1, buf);
    screen->getstringsize(buf, &w, &h);
    x1 += w;

    /* Print out Q part of status line (right justify) */
    if (mode == Q && selected)
        screen->set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID);
    else
        screen->set_drawmode(DRMODE_SOLID);

    snprintf(buf, sizeof(buf), "%d.%d%s", q / EQ_USER_DIVISOR,
             q % EQ_USER_DIVISOR, screen->lcdwidth >= 160 ? " Q" : "");
    screen->getstringsize(buf, &w, &h);
    x2 = x + width - w - 2;
    screen->putsxy(x2, y1, buf);

    /* Print out cutoff part of status line (center between gain & Q) */
    if (mode == CUTOFF && selected)
        screen->set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID);
    else
        screen->set_drawmode(DRMODE_SOLID);

    snprintf(buf, sizeof(buf),  "%5d%s", cutoff,
             screen->lcdwidth >= 160 ? "Hz" : "");
    screen->getstringsize(buf, &w, &h);
    x1 = x1 + (x2 - x1 - w)/2;
    screen->putsxy(x1, y1, buf);

    /* Draw selection box */
    total_height = 3 + h + 1 + SCROLLBAR_SIZE + 3;
    screen->set_drawmode(DRMODE_SOLID);
    if (selected) {
        screen->drawrect(x, y, width, total_height);
    }

    /* Draw horizontal slider. Reuse scrollbar for this */
    gui_scrollbar_draw(screen, x + 3, y1 + h + 1, width - 6, SCROLLBAR_SIZE,
                       steps, min_item, max_item, HORIZONTAL);

    return total_height;
}
Beispiel #5
0
void draw_progressbar(struct gui_wps *gwps, int line, struct progressbar *pb)
{
    struct screen *display = gwps->display;
    struct viewport *vp = pb->vp;
    struct wps_state *state = skin_get_global_state();
    struct mp3entry *id3 = state->id3;
    int x = pb->x, y = pb->y, width = pb->width, height = pb->height;
    unsigned long length, end;
    int flags = HORIZONTAL;
    
    if (height < 0)
        height = font_get(vp->font)->height;

    if (y < 0)
    {
        int line_height = font_get(vp->font)->height;
        /* center the pb in the line, but only if the line is higher than the pb */
        int center = (line_height-height)/2;
        /* if Y was not set calculate by font height,Y is -line_number-1 */
        y = line*line_height + (0 > center ? 0 : center);
    }

    if (pb->type == SKIN_TOKEN_VOLUMEBAR)
    {
        int minvol = sound_min(SOUND_VOLUME);
        int maxvol = sound_max(SOUND_VOLUME);
        length = maxvol-minvol;
        end = global_settings.volume-minvol;
    }
    else if (pb->type == SKIN_TOKEN_BATTERY_PERCENTBAR)
    {
        length = 100;
        end = battery_level();
    }
    else if (pb->type == SKIN_TOKEN_PEAKMETER_LEFTBAR ||
             pb->type == SKIN_TOKEN_PEAKMETER_RIGHTBAR)
    {
        int left, right, val;
        peak_meter_current_vals(&left, &right);
        val = pb->type == SKIN_TOKEN_PEAKMETER_LEFTBAR ? left : right;
        length = MAX_PEAK;
        end = peak_meter_scale_value(val, length);
    }
#if CONFIG_TUNER
    else if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF))
    {
#ifdef HAVE_RADIO_RSSI
        if (pb->type == SKIN_TOKEN_TUNER_RSSI_BAR)
        {
            int val = tuner_get(RADIO_RSSI);
            int min = tuner_get(RADIO_RSSI_MIN);
            int max = tuner_get(RADIO_RSSI_MAX);
            end = val - min;
            length = max - min;
        }
        else
#endif
        {
            int min = fm_region_data[global_settings.fm_region].freq_min;
            end = radio_current_frequency() - min;
            length = fm_region_data[global_settings.fm_region].freq_max - min;
        }
    }
#endif
    else if (id3 && id3->length)
    {
        length = id3->length;
        end = id3->elapsed + state->ff_rewind_count;
    }
    else
    {
        length = 1;
        end = 0;
    }
    
    if (!pb->horizontal)
    {
        /* we want to fill upwards which is technically inverted. */
        flags = INVERTFILL;
    }
    
    if (pb->invert_fill_direction)
    {
        flags ^= INVERTFILL;
    }

    if (pb->nofill)
    {
        flags |= INNER_NOFILL;
    }

    if (pb->slider)
    {
        struct gui_img *img = pb->slider;
        /* clear the slider */
        screen_clear_area(display, x, y, width, height);

        /* shrink the bar so the slider is inside bounds */
        if (flags&HORIZONTAL)
        {
            width -= img->bm.width;
            x += img->bm.width / 2;
        }
        else
        {
            height -= img->bm.height;
            y += img->bm.height / 2;
        }
    }
    
    if (pb->backdrop)
    {
        struct gui_img *img = pb->backdrop;
#if LCD_DEPTH > 1
        if(img->bm.format == FORMAT_MONO) {
#endif
            display->mono_bitmap_part(img->bm.data,
                                      0, 0, img->bm.width,
                                      x, y, width, height);
#if LCD_DEPTH > 1
        } else {
            display->transparent_bitmap_part((fb_data *)img->bm.data,
                                             0, 0,
                                             STRIDE(display->screen_type,
                                             img->bm.width, img->bm.height),
                                             x, y, width, height);
        }
#endif
        flags |= DONT_CLEAR_EXCESS;
    }
    
    if (!pb->nobar)
    {
        if (pb->image)
            gui_bitmap_scrollbar_draw(display, &pb->image->bm,
                                    x, y, width, height,
                                    length, 0, end, flags);
        else
            gui_scrollbar_draw(display, x, y, width, height,
                               length, 0, end, flags);
    }

    if (pb->slider)
    {
        int xoff = 0, yoff = 0;
        int w = width, h = height;
        struct gui_img *img = pb->slider;

        if (flags&HORIZONTAL)
        {
            w = img->bm.width;
            xoff = width * end / length;
            if (flags&INVERTFILL)
                xoff = width - xoff;
            xoff -= w / 2;
        }
        else
        {
            h = img->bm.height;
            yoff = height * end / length;
            if (flags&INVERTFILL)
                yoff = height - yoff;
            yoff -= h / 2;
        }
#if LCD_DEPTH > 1
        if(img->bm.format == FORMAT_MONO) {
#endif
            display->mono_bitmap_part(img->bm.data,
                                      0, 0, img->bm.width,
                                      x + xoff, y + yoff, w, h);
#if LCD_DEPTH > 1
        } else {
            display->transparent_bitmap_part((fb_data *)img->bm.data,
                                             0, 0,
                                             STRIDE(display->screen_type,
                                             img->bm.width, img->bm.height),
                                             x + xoff, y + yoff, w, h);
        }
#endif
    }

    if (pb->type == SKIN_TOKEN_PROGRESSBAR)
    {
        if (id3 && id3->length)
        {
#ifdef AB_REPEAT_ENABLE
            if (ab_repeat_mode_enabled())
                ab_draw_markers(display, id3->length, x, y, width, height);
#endif

            if (id3->cuesheet)
                cue_draw_markers(display, id3->cuesheet, id3->length,
                                 x, y+1, width, height-2);
        }
#if 0 /* disable for now CONFIG_TUNER */
        else if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF))
        {
            presets_draw_markers(display, x, y, width, height);
        }
#endif
    }
}
Beispiel #6
0
void draw_progressbar(struct gui_wps *gwps, int line, struct progressbar *pb)
{
    struct screen *display = gwps->display;
    struct viewport *vp = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->vp);
    struct wps_state *state = skin_get_global_state();
    struct mp3entry *id3 = state->id3;
    int x = pb->x, y = pb->y, width = pb->width, height = pb->height;
    unsigned long length, end;
    int flags = HORIZONTAL;
    
    if (height < 0)
        height = font_get(vp->font)->height;

    if (y < 0)
    {
        int line_height = font_get(vp->font)->height;
        /* center the pb in the line, but only if the line is higher than the pb */
        int center = (line_height-height)/2;
        /* if Y was not set calculate by font height,Y is -line_number-1 */
        y = line*line_height + (0 > center ? 0 : center);
    }

    if (pb->type == SKIN_TOKEN_VOLUMEBAR)
    {
        int minvol = sound_min(SOUND_VOLUME);
        int maxvol = sound_max(SOUND_VOLUME);
        length = maxvol-minvol;
        end = global_settings.volume-minvol;
    }
    else if (pb->type == SKIN_TOKEN_BATTERY_PERCENTBAR)
    {
        length = 100;
        end = battery_level();
    }
    else if (pb->type == SKIN_TOKEN_PEAKMETER_LEFTBAR ||
             pb->type == SKIN_TOKEN_PEAKMETER_RIGHTBAR)
    {
        int left, right, val;
        peak_meter_current_vals(&left, &right);
        val = pb->type == SKIN_TOKEN_PEAKMETER_LEFTBAR ? left : right;
        length = MAX_PEAK;
        end = peak_meter_scale_value(val, length);
    }
    else if (pb->type == SKIN_TOKEN_LIST_SCROLLBAR)
    {
        int val, min, max;
        skinlist_get_scrollbar(&val, &min, &max);
        end = val - min;
        length = max - min;
    }
    else if (pb->type == SKIN_TOKEN_SETTINGBAR)
    {
        int val, count;
        get_setting_info_for_bar(pb->setting_id, &count, &val);
        length = count - 1;
        end = val;
    }
#if CONFIG_TUNER
    else if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF))
    {
#ifdef HAVE_RADIO_RSSI
        if (pb->type == SKIN_TOKEN_TUNER_RSSI_BAR)
        {
            int val = tuner_get(RADIO_RSSI);
            int min = tuner_get(RADIO_RSSI_MIN);
            int max = tuner_get(RADIO_RSSI_MAX);
            end = val - min;
            length = max - min;
        }
        else
#endif
        {
            int min = fm_region_data[global_settings.fm_region].freq_min;
            end = radio_current_frequency() - min;
            length = fm_region_data[global_settings.fm_region].freq_max - min;
        }
    }
#endif
    else if (id3 && id3->length)
    {
        length = id3->length;
        end = id3->elapsed + state->ff_rewind_count;
    }
    else
    {
        length = 1;
        end = 0;
    }
    
    if (!pb->horizontal)
    {
        /* we want to fill upwards which is technically inverted. */
        flags = INVERTFILL;
    }
    
    if (pb->invert_fill_direction)
    {
        flags ^= INVERTFILL;
    }

    if (pb->nofill)
    {
        flags |= INNER_NOFILL;
    }

    if (SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->slider))
    {
        struct gui_img *img = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->slider);
        /* clear the slider */
        screen_clear_area(display, x, y, width, height);

        /* account for the sliders width in the progressbar */
        if (flags&HORIZONTAL)
        {
            width -= img->bm.width;
        }
        else
        {
            height -= img->bm.height;
        }
    }

    if (SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->backdrop))
    {
        struct gui_img *img = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->backdrop);
        img->bm.data = core_get_data(img->buflib_handle);
        display->bmp_part(&img->bm, 0, 0, x, y, pb->width, height);
        flags |= DONT_CLEAR_EXCESS;
    }

    if (!pb->nobar)
    {
        struct gui_img *img = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->image);
        if (img)
        {
            char *img_data = core_get_data(img->buflib_handle);
            img->bm.data = img_data;
            gui_bitmap_scrollbar_draw(display, &img->bm,
                                    x, y, width, height,
                                    length, 0, end, flags);
        }
        else
            gui_scrollbar_draw(display, x, y, width, height,
                               length, 0, end, flags);
    }

    if (SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->slider))
    {
        int xoff = 0, yoff = 0;
        int w = width, h = height;
        struct gui_img *img = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->slider);
        img->bm.data = core_get_data(img->buflib_handle);

        if (flags&HORIZONTAL)
        {
            w = img->bm.width;
            xoff = width * end / length;
            if (flags&INVERTFILL)
                xoff = width - xoff;
        }
        else
        {
            h = img->bm.height;
            yoff = height * end / length;
            if (flags&INVERTFILL)
                yoff = height - yoff;
        }
        display->bmp_part(&img->bm, 0, 0, x + xoff, y + yoff, w, h);
    }

    if (pb->type == SKIN_TOKEN_PROGRESSBAR)
    {
        if (id3 && id3->length)
        {
#ifdef AB_REPEAT_ENABLE
            if (ab_repeat_mode_enabled())
                ab_draw_markers(display, id3->length, x, y, width, height);
#endif

            if (id3->cuesheet)
                cue_draw_markers(display, id3->cuesheet, id3->length,
                                 x, y+1, width, height-2);
        }
#if 0 /* disable for now CONFIG_TUNER */
        else if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF))
        {
            presets_draw_markers(display, x, y, width, height);
        }
#endif
    }
}
static void draw_screen(struct screen *display, char *title,
                        struct rgb_pick *rgb, int row)
{
    unsigned  text_color       = LCD_BLACK;
    unsigned  background_color = LCD_WHITE;
    char      buf[32];
    int       i, char_height, line_height;
    int       max_label_width;
    int       text_x, text_top;
    int       slider_x, slider_width;
    bool      display_three_rows;
    struct viewport vp;

    viewport_set_defaults(&vp, display->screen_type);
    display->set_viewport(&vp);

    display->clear_viewport();

    if (display->depth > 1)
    {
        text_color       = display->get_foreground();
        background_color = display->get_background();
    }

    /* Draw title string */
    set_drawinfo(display, DRMODE_SOLID, text_color, background_color);
    vp.flags |= VP_FLAG_ALIGN_CENTER;
    display->putsxy(0, MARGIN_TOP, title);

    /* Get slider positions and top starting position */
    max_label_width = label_get_max_width(display);
    char_height  = display->getcharheight();
    text_top     = MARGIN_TOP + char_height +
                   TITLE_MARGIN_BOTTOM + SELECTOR_TB_MARGIN;
    text_x       = SELECTOR_WIDTH;
    slider_x     = text_x + max_label_width + SLIDER_TEXT_MARGIN;
    slider_width = vp.width - slider_x*2 - max_label_width;
    line_height  = char_height + 2*SELECTOR_TB_MARGIN;

    /* Find out if there's enough room for three sliders or just
       enough to display the selected slider - calculate total height
       of display with three sliders present */
    display_three_rows =
        vp.height >=
            text_top + line_height*3  + /* Title + 3 sliders     */
            SWATCH_TOP_MARGIN         + /* at least 2 lines      */
            char_height*2             + /*  + margins for bottom */
            MARGIN_BOTTOM;              /* colored rectangle     */

    for (i = 0; i < 3; i++)
    {
        unsigned sb_flags = HORIZONTAL;
        int      mode     = DRMODE_SOLID;
        unsigned fg       = text_color;
        unsigned bg       = background_color;

        if (i == row)
        {
            set_drawinfo(display, DRMODE_SOLID, text_color, background_color);

            if (global_settings.cursor_style != 0)
            {
                /* Draw solid bar selection bar */
                display->fillrect(0,
                                  text_top - SELECTOR_TB_MARGIN,
                                  vp.width,
                                  char_height + SELECTOR_TB_MARGIN*2);

                if (display->depth < 16)
                {
                    sb_flags |= FOREGROUND | INNER_FILL;
                    mode     |= DRMODE_INVERSEVID;
                }
            }
            else if (display_three_rows)
            {
                /* Draw ">    <" around sliders */
                int top = text_top + (char_height - SELECTOR_HEIGHT) / 2;
                screen_put_iconxy(display, 0, top, Icon_Cursor);
                screen_put_iconxy(display,
                                  vp.width - SELECTOR_WIDTH,
                                  top, Icon_Cursor);
            }

            if (display->depth >= 16)
            {
                sb_flags |= FOREGROUND | INNER_BGFILL;
                mode      = DRMODE_FG;
                fg        = prim_rgb[SB_PRIM][i];
                bg        = prim_rgb[SB_FILL][i];
            }
        }
        else if (!display_three_rows)
            continue;

        set_drawinfo(display, mode, fg, bg);

        /* Draw label */
        buf[0] = str(LANG_COLOR_RGB_LABELS)[i];
        buf[1] = '\0';
        vp.flags &= ~VP_FLAG_ALIGNMENT_MASK;
        display->putsxy(text_x, text_top, buf);
        /* Draw color value */
        snprintf(buf, 3, "%02d", rgb->rgb_val[i]);
        vp.flags |= VP_FLAG_ALIGN_RIGHT;
        display->putsxy(text_x, text_top, buf);

        /* Draw scrollbar */
        gui_scrollbar_draw(display,                     /* screen */
                           slider_x,                    /* x */
                           text_top + char_height / 4,  /* y */
                           slider_width,                /* width */
                           char_height / 2,             /* height */
                           rgb_max[i],                  /* items */
                           0,                           /* min_shown */
                           rgb->rgb_val[i],             /* max_shown */
                           sb_flags);                   /* flags */

        /* Advance to next line */
        text_top += line_height;
    } /* end for */

    /* Format RGB: #rrggbb */
    snprintf(buf, sizeof(buf), str(LANG_COLOR_RGB_VALUE),
                               rgb->red, rgb->green, rgb->blue);
    vp.flags |= VP_FLAG_ALIGN_CENTER;
    if (display->depth >= 16)
    {
        /* Display color swatch on color screens only */
        int top    = text_top + SWATCH_TOP_MARGIN;
        int width  = vp.width - text_x*2;
        int height = vp.height - top - MARGIN_BOTTOM;

        /* Only draw if room */
        if (height >= char_height + 2)
        {
            /* draw the big rectangle */
            display->set_foreground(rgb->color);
            display->fillrect(text_x, top, width, height);

            /* Draw RGB: #rrggbb in middle of swatch */
            set_drawinfo(display, DRMODE_FG, get_black_or_white(rgb),
                         background_color);

            display->putsxy(0, top + (height - char_height) / 2, buf);

            /* Draw border around the rect */
            set_drawinfo(display, DRMODE_SOLID, text_color, background_color);
            display->drawrect(text_x, top, width, height);
        }
    }
    else
    {
        /* Display RGB value only centered on remaining display if room */
        int top = text_top + SWATCH_TOP_MARGIN;
        int height = vp.height - top - MARGIN_BOTTOM;

        if (height >= char_height)
        {
            set_drawinfo(display, DRMODE_SOLID, text_color, background_color);
            display->putsxy(0, top + (height - char_height) / 2, buf);
        }
    }

    display->update_viewport();
    display->set_viewport(NULL);
}