835 lines
17 KiB
C
835 lines
17 KiB
C
/* $NetBSD: slk.c,v 1.8 2019/07/28 00:51:59 uwe Exp $ */
|
|
|
|
/*-
|
|
* Copyright (c) 2017 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
* by Roy Marples.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
#ifndef lint
|
|
__RCSID("$NetBSD: slk.c,v 1.8 2019/07/28 00:51:59 uwe Exp $");
|
|
#endif /* not lint */
|
|
|
|
#include <ctype.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#ifdef HAVE_WCHAR
|
|
#include <wctype.h>
|
|
#endif
|
|
|
|
#include "curses.h"
|
|
#include "curses_private.h"
|
|
|
|
/* Terminals with real soft labels have NOT been tested.
|
|
* If you have such a device, please let us know so this comment
|
|
* can be adjusted. */
|
|
|
|
/* POSIX says that each label can be up to 8 columns.
|
|
* However, our implementation can allow labels to expand beyond that. */
|
|
//#define SLK_SIZE_DYNAMIC
|
|
#ifdef SLK_SIZE_DYNAMIC
|
|
#define SLK_SIZE MAX_SLK_LABEL
|
|
#else
|
|
#define SLK_SIZE MAX_SLK_COLS
|
|
#endif
|
|
|
|
static int slk_fmt = SLK_FMT_INVAL; /* fmt of slk_init */
|
|
|
|
/* Safe variants of public functions. */
|
|
static int __slk_attroff(SCREEN *, const chtype);
|
|
static int __slk_attron(SCREEN *, const chtype);
|
|
static int __slk_attrset(SCREEN *, const chtype);
|
|
#ifdef HAVE_WCHAR
|
|
static int __slk_attr_off(SCREEN *, const attr_t, void *);
|
|
static int __slk_attr_on(SCREEN *, const attr_t, void *);
|
|
static int __slk_attr_set(SCREEN *, const attr_t, short, void *opt);
|
|
static int __slk_color(SCREEN *, short);
|
|
#endif
|
|
|
|
static int __slk_clear(SCREEN *);
|
|
static char *__slk_label(SCREEN *, int);
|
|
static int __slk_restore(SCREEN *);
|
|
static int __slk_set(SCREEN *, int, const char *, int);
|
|
static int __slk_touch(SCREEN *);
|
|
#ifdef HAVE_WCHAR
|
|
static int __slk_wset(SCREEN *, int, const wchar_t *, int);
|
|
#endif
|
|
|
|
/* Internal engine parts. */
|
|
static int __slk_ripoffline(WINDOW *, int);
|
|
static int __slk_set_finalise(SCREEN *, int);
|
|
static int __slk_draw(SCREEN *, int);
|
|
static int __slk_redraw(SCREEN *);
|
|
|
|
/*
|
|
* slk_init --
|
|
* Init Soft Label Keys.
|
|
*/
|
|
int
|
|
slk_init(int fmt)
|
|
{
|
|
|
|
switch(fmt) {
|
|
case SLK_FMT_3_2_3:
|
|
case SLK_FMT_4_4:
|
|
break;
|
|
default:
|
|
return ERR;
|
|
}
|
|
|
|
slk_fmt = fmt;
|
|
/* Even if the terminal supports soft label keys directly,
|
|
* we need to reserve a line. */
|
|
return ripoffline(-1, __slk_ripoffline);
|
|
}
|
|
|
|
/*
|
|
* slk_attron --
|
|
* Test and set attributes on ripped off slk window.
|
|
*/
|
|
int
|
|
slk_attron(const chtype attr)
|
|
{
|
|
|
|
return __slk_attron(_cursesi_screen, attr);
|
|
}
|
|
|
|
#ifdef HAVE_WCHAR
|
|
/*
|
|
* slk_attr_on --
|
|
* Test and set wide attributes on ripped off slk window.
|
|
*/
|
|
int
|
|
slk_attr_on(const attr_t attr, void *opt)
|
|
{
|
|
|
|
return __slk_attr_on(_cursesi_screen, attr, opt);
|
|
}
|
|
#endif /* HAVE_WCHAR */
|
|
|
|
/*
|
|
* slk_attroff --
|
|
* Test and unset attributes on ripped off slk window.
|
|
*/
|
|
int
|
|
slk_attroff(const chtype attr)
|
|
{
|
|
|
|
return __slk_attroff(_cursesi_screen, attr);
|
|
}
|
|
|
|
#ifdef HAVE_WCHAR
|
|
/*
|
|
* slk_attr_off --
|
|
* Test and unset wide attributes on ripped off slk window.
|
|
*/
|
|
int
|
|
slk_attr_off(const attr_t attr, void *opt)
|
|
{
|
|
|
|
return __slk_attr_off(_cursesi_screen, attr, opt);
|
|
}
|
|
#endif /* HAVE_WCHAR */
|
|
|
|
/*
|
|
* slk_attrset --
|
|
* Set attributes and color pair on ripped off slk window.
|
|
*/
|
|
int
|
|
slk_attrset(const chtype attr)
|
|
{
|
|
|
|
return __slk_attrset(_cursesi_screen, attr);
|
|
}
|
|
|
|
#ifdef HAVE_WCHAR
|
|
/*
|
|
* slk_attr_set --
|
|
* Set wide attributes and color pair on ripped off slk window.
|
|
*/
|
|
int
|
|
slk_attr_set(const attr_t attr, short pair, void *opt)
|
|
{
|
|
|
|
return __slk_attr_set(_cursesi_screen, attr, pair, opt);
|
|
}
|
|
#endif /* HAVE_WCHAR */
|
|
|
|
/*
|
|
* slk_clear --
|
|
* Clear slk from the current screen.
|
|
*/
|
|
int
|
|
slk_clear(void)
|
|
{
|
|
|
|
return __slk_clear(_cursesi_screen);
|
|
}
|
|
|
|
#ifdef HAVE_WCHAR
|
|
/*
|
|
* slk_color --
|
|
* Set color pair on ripped off slk window.
|
|
*/
|
|
int
|
|
slk_color(short pair)
|
|
{
|
|
|
|
return __slk_color(_cursesi_screen, pair);
|
|
}
|
|
#endif /* HAVE_WCHAR */
|
|
|
|
/*
|
|
* slk_label --
|
|
* Return a pointer to the saved label for key labnum.
|
|
*/
|
|
char *
|
|
slk_label(int labnum)
|
|
{
|
|
|
|
return __slk_label(_cursesi_screen, labnum);
|
|
}
|
|
|
|
/*
|
|
* slk_wnoutrefresh --
|
|
* Add the contents of the ripped off slk window to the virtual window.
|
|
*/
|
|
int
|
|
slk_noutrefresh(void)
|
|
{
|
|
|
|
return __slk_noutrefresh(_cursesi_screen);
|
|
}
|
|
|
|
/*
|
|
* slk_refresh --
|
|
* Force a refresh for the ripped off slk window.
|
|
*/
|
|
int
|
|
slk_refresh(void)
|
|
{
|
|
|
|
if (slk_noutrefresh() == ERR)
|
|
return ERR;
|
|
return doupdate();
|
|
}
|
|
|
|
/*
|
|
* slk_restore --
|
|
* Retore slk to the screen after a slk_clear.
|
|
*/
|
|
int
|
|
slk_restore(void)
|
|
{
|
|
|
|
return __slk_restore(_cursesi_screen);
|
|
}
|
|
|
|
/*
|
|
* slk_set --
|
|
* Sets the text of the label specified by labnum
|
|
* and how it is displayed.
|
|
*/
|
|
int
|
|
slk_set(int labnum, const char *label, int justify)
|
|
{
|
|
|
|
return __slk_set(_cursesi_screen, labnum, label, justify);
|
|
}
|
|
|
|
/*
|
|
* slk_touch --
|
|
* Sets the ripped off slk window as modified.
|
|
*/
|
|
int
|
|
slk_touch(void)
|
|
{
|
|
|
|
return __slk_touch(_cursesi_screen);
|
|
}
|
|
|
|
#ifdef HAVE_WCHAR
|
|
/*
|
|
* slk_wset --
|
|
* Sets the wide text of the label specified by labnum
|
|
* and how it is displayed.
|
|
*/
|
|
int
|
|
slk_wset(int labnum, const wchar_t *label, int justify)
|
|
{
|
|
|
|
return __slk_wset(_cursesi_screen, labnum, label, justify);
|
|
}
|
|
#endif /* HAVE_WCHAR */
|
|
|
|
/*
|
|
* __slk_attron --
|
|
* Test and set attributes on ripped off slk window.
|
|
*/
|
|
static int
|
|
__slk_attron(SCREEN *screen, const chtype attr)
|
|
{
|
|
|
|
if (screen == NULL || screen->slk_window == NULL)
|
|
return ERR;
|
|
return wattron(screen->slk_window, attr);
|
|
}
|
|
|
|
#ifdef HAVE_WCHAR
|
|
/*
|
|
* __slk_attr_on --
|
|
* Test and set wide attributes on ripped off slk window.
|
|
*/
|
|
static int
|
|
__slk_attr_on(SCREEN *screen, const attr_t attr, void *opt)
|
|
{
|
|
|
|
if (screen == NULL || screen->slk_window == NULL)
|
|
return ERR;
|
|
return wattr_on(screen->slk_window, attr, opt);
|
|
}
|
|
#endif /* HAVE_WCHAR */
|
|
|
|
/*
|
|
* __slk_attroff --
|
|
* Test and unset attributes on ripped off slk window.
|
|
*/
|
|
static int
|
|
__slk_attroff(SCREEN *screen, const chtype attr)
|
|
{
|
|
|
|
if (screen == NULL || screen->slk_window == NULL)
|
|
return ERR;
|
|
return wattroff(screen->slk_window, attr);
|
|
}
|
|
|
|
#ifdef HAVE_WCHAR
|
|
/*
|
|
* __slk_attr_off --
|
|
* Test and unset wide attributes on ripped off slk window.
|
|
*/
|
|
static int
|
|
__slk_attr_off(SCREEN *screen, const attr_t attr, void *opt)
|
|
{
|
|
|
|
if (screen == NULL || screen->slk_window == NULL)
|
|
return ERR;
|
|
return wattr_off(screen->slk_window, attr, opt);
|
|
}
|
|
#endif /* HAVE_WCHAR */
|
|
|
|
/*
|
|
* __slk_attrset --
|
|
* Set attributes and color pair on ripped off slk window.
|
|
*/
|
|
static int
|
|
__slk_attrset(SCREEN *screen, const chtype attr)
|
|
{
|
|
|
|
if (screen == NULL || screen->slk_window == NULL)
|
|
return ERR;
|
|
return wattrset(screen->slk_window, attr);
|
|
}
|
|
|
|
#ifdef HAVE_WCHAR
|
|
/*
|
|
* __slk_attr_set --
|
|
* Set wide attributes and color pair on ripped off slk window.
|
|
*/
|
|
static int
|
|
__slk_attr_set(SCREEN *screen, const attr_t attr, short pair, void *opt)
|
|
{
|
|
|
|
if (screen == NULL || screen->slk_window == NULL)
|
|
return ERR;
|
|
return wattr_set(screen->slk_window, attr, pair, opt);
|
|
}
|
|
#endif /* HAVE_WCHAR */
|
|
|
|
/*
|
|
* __slk_clear --
|
|
* Clear slk from the current screen.
|
|
*/
|
|
static int
|
|
__slk_clear(SCREEN *screen)
|
|
{
|
|
|
|
if (screen == NULL)
|
|
return ERR;
|
|
screen->slk_hidden = true;
|
|
if (screen->is_term_slk) {
|
|
if (t_label_off(screen->term) == NULL)
|
|
return ERR;
|
|
return ti_putp(screen->term,
|
|
ti_tiparm(screen->term, t_label_off(screen->term)));
|
|
}
|
|
if (screen->slk_window == NULL)
|
|
return ERR;
|
|
werase(screen->slk_window);
|
|
return wrefresh(screen->slk_window);
|
|
}
|
|
|
|
#ifdef HAVE_WCHAR
|
|
/*
|
|
* __slk_color --
|
|
* Set color pair on ripped off slk window.
|
|
*/
|
|
static int
|
|
__slk_color(SCREEN *screen, short pair)
|
|
{
|
|
|
|
if (screen == NULL || screen->slk_window == NULL)
|
|
return ERR;
|
|
return wcolor_set(screen->slk_window, pair, NULL);
|
|
}
|
|
#endif /* HAVE_WCHAR */
|
|
|
|
/*
|
|
* __slk_label --
|
|
* Return a pointer to the saved label for key labnum.
|
|
*/
|
|
static char *
|
|
__slk_label(SCREEN *screen, int labnum)
|
|
{
|
|
|
|
if (screen == NULL || labnum < 1 || labnum > screen->slk_nlabels)
|
|
return NULL;
|
|
return screen->slk_labels[--labnum].text;
|
|
}
|
|
|
|
/*
|
|
* __slk_wnoutrefresh --
|
|
* Add the contents of the ripped off slk window to the virtual window.
|
|
*/
|
|
int
|
|
__slk_noutrefresh(SCREEN *screen)
|
|
{
|
|
|
|
if (screen == NULL || screen->slk_window == NULL)
|
|
return ERR;
|
|
return wnoutrefresh(screen->slk_window);
|
|
}
|
|
|
|
/*
|
|
* __slk_restore --
|
|
* Retore slk to the screen after a slk_clear.
|
|
*/
|
|
static int
|
|
__slk_restore(SCREEN *screen)
|
|
{
|
|
|
|
if (screen == NULL)
|
|
return ERR;
|
|
screen->slk_hidden = false;
|
|
if (screen->is_term_slk) {
|
|
if (t_label_on(screen->term) == NULL)
|
|
return ERR;
|
|
return ti_putp(screen->term,
|
|
ti_tiparm(screen->term, t_label_on(screen->term)));
|
|
}
|
|
if (screen->slk_window == NULL)
|
|
return ERR;
|
|
if (__slk_redraw(screen) == ERR)
|
|
return ERR;
|
|
return wrefresh(screen->slk_window);
|
|
}
|
|
|
|
/*
|
|
* __slk_set --
|
|
* Sets the text of the label specified by labnum
|
|
* and how it is displayed.
|
|
*/
|
|
static int
|
|
__slk_set(SCREEN *screen, int labnum, const char *label, int justify)
|
|
{
|
|
struct __slk_label *l;
|
|
const char *end;
|
|
size_t len;
|
|
char *text;
|
|
#ifdef HAVE_WCHAR
|
|
wchar_t wc;
|
|
size_t wc_len;
|
|
#endif
|
|
|
|
/* Check args. */
|
|
if (screen == NULL || labnum < 1 || labnum > screen->slk_nlabels)
|
|
return ERR;
|
|
switch(justify) {
|
|
case SLK_JUSTIFY_LEFT:
|
|
case SLK_JUSTIFY_CENTER:
|
|
case SLK_JUSTIFY_RIGHT:
|
|
break;
|
|
default:
|
|
return ERR;
|
|
}
|
|
if (label == NULL)
|
|
label = "";
|
|
|
|
/* Skip leading whitespace. */
|
|
while(isspace((unsigned char)*label))
|
|
label++;
|
|
/* Grab end. */
|
|
end = label;
|
|
|
|
#ifdef HAVE_WCHAR
|
|
size_t endlen = strlen(end);
|
|
while (*end != '\0') {
|
|
wc_len = mbrtowc(&wc, end, endlen, &screen->sp);
|
|
if ((ssize_t)wc_len < 0)
|
|
return ERR;
|
|
if (!iswprint((wint_t)wc))
|
|
break;
|
|
end += wc_len;
|
|
endlen -= wc_len;
|
|
}
|
|
#else
|
|
while(isprint((unsigned char)*end))
|
|
end++;
|
|
#endif
|
|
len = end - label;
|
|
|
|
/* Take a backup, in-case we can grow the label. */
|
|
if ((text = strndup(label, len)) == NULL)
|
|
return ERR;
|
|
|
|
/* All checks out, assign. */
|
|
l = &screen->slk_labels[--labnum]; /* internal zero based index */
|
|
l->text = text;
|
|
l->justify = justify;
|
|
|
|
__slk_set_finalise(screen, labnum);
|
|
return OK;
|
|
}
|
|
|
|
/*
|
|
* __slk_touch --
|
|
* Sets the ripped off slk window as modified.
|
|
*/
|
|
static int
|
|
__slk_touch(SCREEN *screen)
|
|
{
|
|
|
|
if (screen == NULL || screen->slk_window == NULL)
|
|
return ERR;
|
|
return touchwin(screen->slk_window);
|
|
}
|
|
|
|
|
|
#ifdef HAVE_WCHAR
|
|
/*
|
|
* __slk_wset --
|
|
* Sets the wide text of the label specified by labnum
|
|
* and how it is displayed.
|
|
*/
|
|
static int
|
|
__slk_wset(SCREEN *screen, int labnum, const wchar_t *label, int justify)
|
|
{
|
|
const wchar_t *olabel;
|
|
size_t len;
|
|
char *str;
|
|
int result = ERR;
|
|
|
|
if (screen == NULL)
|
|
return ERR;
|
|
olabel = label;
|
|
if ((len = wcsrtombs(NULL, &olabel, 0, &screen->sp)) == -1)
|
|
return ERR;
|
|
len++; /* We need to store the NULL character. */
|
|
if ((str = malloc(len)) == NULL)
|
|
return ERR;
|
|
olabel = label;
|
|
if (wcsrtombs(str, &olabel, len, &screen->sp) == -1)
|
|
goto out;
|
|
result = __slk_set(screen, labnum, str, justify);
|
|
out:
|
|
free(str);
|
|
return result;
|
|
}
|
|
#endif /* HAVE_WCHAR */
|
|
|
|
|
|
/*
|
|
* __slk_init --
|
|
* Allocate structures.
|
|
*/
|
|
int
|
|
__slk_init(SCREEN *screen)
|
|
{
|
|
|
|
__slk_free(screen); /* safety */
|
|
|
|
screen->slk_format = slk_fmt;
|
|
if (slk_fmt == SLK_FMT_INVAL)
|
|
return OK;
|
|
slk_fmt = SLK_FMT_INVAL;
|
|
|
|
switch(screen->slk_format) {
|
|
case SLK_FMT_3_2_3:
|
|
case SLK_FMT_4_4:
|
|
screen->slk_nlabels = 8;
|
|
break;
|
|
default: /* impossible */
|
|
return ERR;
|
|
}
|
|
|
|
screen->slk_labels = calloc(screen->slk_nlabels,
|
|
sizeof(*screen->slk_labels));
|
|
if (screen->slk_labels == NULL)
|
|
return ERR;
|
|
|
|
screen->is_term_slk =
|
|
t_plab_norm(screen->term) != NULL &&
|
|
t_num_labels(screen->term) > 0;
|
|
if (screen->is_term_slk) {
|
|
__unripoffline(__slk_ripoffline);
|
|
screen->slk_nlabels = t_num_labels(screen->term);
|
|
screen->slk_label_len = t_label_width(screen->term);
|
|
/* XXX label_height, label_format? */
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*
|
|
* __slk_free --
|
|
* Free allocates resources.
|
|
*/
|
|
void
|
|
__slk_free(SCREEN *screen)
|
|
{
|
|
int i;
|
|
|
|
if (screen->slk_window != NULL)
|
|
delwin(screen->slk_window);
|
|
for (i = 0; i < screen->slk_nlabels; i++)
|
|
free(screen->slk_labels[i].text);
|
|
free(screen->slk_labels);
|
|
}
|
|
|
|
/*
|
|
* __slk_ripoffline --
|
|
* ripoffline callback to accept a WINDOW to create our keys.
|
|
*/
|
|
static int
|
|
__slk_ripoffline(WINDOW *window, int cols)
|
|
{
|
|
|
|
if (window == NULL)
|
|
return ERR;
|
|
window->screen->slk_window = window;
|
|
wattron(window,
|
|
(t_no_color_video(window->screen->term) & 1) == 0
|
|
? A_STANDOUT : A_REVERSE);
|
|
__slk_resize(window->screen, cols);
|
|
return OK;
|
|
}
|
|
|
|
/*
|
|
* __slk_resize --
|
|
* Size and position the labels in the ripped off slk window.
|
|
*/
|
|
int
|
|
__slk_resize(SCREEN *screen, int cols)
|
|
{
|
|
int x = 0;
|
|
struct __slk_label *l;
|
|
|
|
if (screen == NULL)
|
|
return ERR;
|
|
if (screen->is_term_slk || screen->slk_nlabels == 0)
|
|
return OK;
|
|
|
|
screen->slk_label_len = (cols / screen->slk_nlabels) - 1;
|
|
if (screen->slk_label_len > SLK_SIZE)
|
|
screen->slk_label_len = SLK_SIZE;
|
|
|
|
l = screen->slk_labels;
|
|
|
|
switch(screen->slk_format) {
|
|
case SLK_FMT_3_2_3:
|
|
/* Left 3 */
|
|
(l++)->x = x;
|
|
(l++)->x = (x += screen->slk_label_len + 1);
|
|
(l++)->x = (x += screen->slk_label_len + 1);
|
|
|
|
/* Middle 2 */
|
|
x = cols / 2;
|
|
(l++)->x = x -(screen->slk_label_len + 1);
|
|
(l++)->x = x + 1;
|
|
|
|
/* Right 3 */
|
|
x = (cols - ((screen->slk_label_len + 1) * 3)) + 1;
|
|
(l++)->x = x;
|
|
(l++)->x = (x += screen->slk_label_len + 1);
|
|
(l++)->x = (x += screen->slk_label_len + 1);
|
|
break;
|
|
|
|
case SLK_FMT_4_4:
|
|
{
|
|
int i, half;
|
|
|
|
half = screen->slk_nlabels / 2;
|
|
for (i = 0; i < screen->slk_nlabels; i++) {
|
|
(l++)->x = x;
|
|
x += screen->slk_label_len;
|
|
/* Split labels in half */
|
|
if (i == half - 1)
|
|
x = cols - (screen->slk_label_len * half) + 1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Write text to the labels. */
|
|
for (x = 0; x < screen->slk_nlabels; x++)
|
|
__slk_set_finalise(screen, x);
|
|
|
|
return __slk_redraw(screen);
|
|
}
|
|
|
|
/*
|
|
* __slk_set_finalise --
|
|
* Does the grunt work of positioning and sizing the text in the label.
|
|
*/
|
|
static int
|
|
__slk_set_finalise(SCREEN *screen, int labnum)
|
|
{
|
|
struct __slk_label *l;
|
|
size_t spc, len, width, x;
|
|
char *p;
|
|
|
|
l = &screen->slk_labels[labnum];
|
|
spc = screen->slk_label_len;
|
|
|
|
#ifdef HAVE_WCHAR
|
|
len = 0;
|
|
width = 0;
|
|
if (l->text != NULL) {
|
|
size_t plen;
|
|
|
|
p = l->text;
|
|
plen = strlen(l->text);
|
|
while (*p != '\0') {
|
|
size_t mblen;
|
|
wchar_t wc;
|
|
int w;
|
|
|
|
mblen = mbrtowc(&wc, p, plen, &screen->sp);
|
|
if ((ssize_t)mblen < 0)
|
|
return ERR;
|
|
w = wcwidth(wc);
|
|
if (width + w > spc)
|
|
break;
|
|
width += w;
|
|
len += mblen;
|
|
p += mblen;
|
|
plen -= mblen;
|
|
}
|
|
}
|
|
#else
|
|
len = l->text == NULL ? 0 : strlen(l->text);
|
|
if (len > spc)
|
|
len = spc;
|
|
width = len;
|
|
#endif
|
|
|
|
switch(l->justify) {
|
|
case SLK_JUSTIFY_LEFT:
|
|
x = 0;
|
|
break;
|
|
case SLK_JUSTIFY_CENTER:
|
|
x = (spc - width) / 2;
|
|
if (x + width > spc)
|
|
x--;
|
|
break;
|
|
case SLK_JUSTIFY_RIGHT:
|
|
x = spc - width;
|
|
break;
|
|
default:
|
|
return ERR; /* impossible */
|
|
}
|
|
|
|
p = l->label;
|
|
if (x != 0) {
|
|
memset(p, ' ', x);
|
|
p += x;
|
|
spc -= x;
|
|
}
|
|
if (len != 0) {
|
|
memcpy(p, l->text, len);
|
|
p += len;
|
|
spc -= width;
|
|
}
|
|
if (spc != 0) {
|
|
memset(p, ' ', spc);
|
|
p += spc;
|
|
}
|
|
*p = '\0'; /* Terminate for plab_norm. */
|
|
|
|
return __slk_draw(screen, labnum);
|
|
}
|
|
|
|
/*
|
|
* __slk_draw --
|
|
* Draws the specified key.
|
|
*/
|
|
static int
|
|
__slk_draw(SCREEN *screen, int labnum)
|
|
{
|
|
const struct __slk_label *l;
|
|
|
|
if (screen->slk_hidden)
|
|
return OK;
|
|
|
|
l = &screen->slk_labels[labnum];
|
|
if (screen->is_term_slk)
|
|
return ti_putp(screen->term,
|
|
ti_tiparm(screen->term,
|
|
t_plab_norm(screen->term), labnum + 1, l->label));
|
|
else if (screen->slk_window != NULL)
|
|
return mvwaddnstr(screen->slk_window, 0, l->x,
|
|
l->label, screen->slk_label_len);
|
|
else
|
|
return ERR;
|
|
}
|
|
|
|
/*
|
|
* __slk_draw --
|
|
* Draws all the keys.
|
|
*/
|
|
static int
|
|
__slk_redraw(SCREEN *screen)
|
|
{
|
|
int i, result = OK;
|
|
|
|
for (i = 0; i < screen->slk_nlabels; i++) {
|
|
if (__slk_draw(screen, i) == ERR)
|
|
result = ERR;
|
|
}
|
|
return result;
|
|
}
|