/**************************************************************************** * apps/graphics/pdcurses/pdc_slk.c * Public Domain Curses * RCSID("$Id: slk.c,v 1.61 2008/07/13 16:08:18 wmcbrine Exp $") * * Copyright (C) 2017 Gregory Nutt. All rights reserved. * Adapted by: Gregory Nutt * * Adapted from the original public domain pdcurses by Gregory Nutt and * released as part of NuttX under the 3-clause BSD license: * * 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. * 3. Neither the name NuttX nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 * COPYRIGHT OWNER 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. * ****************************************************************************/ /* Name: slk * * Synopsis: * int slk_init(int fmt); * int slk_set(int labnum, const char *label, int justify); * int slk_refresh(void); * int slk_noutrefresh(void); * char *slk_label(int labnum); * int slk_clear(void); * int slk_restore(void); * int slk_touch(void); * int slk_attron(const chtype attrs); * int slk_attr_on(const attr_t attrs, void *opts); * int slk_attrset(const chtype attrs); * int slk_attr_set(const attr_t attrs, short color_pair, void *opts); * int slk_attroff(const chtype attrs); * int slk_attr_off(const attr_t attrs, void *opts); * int slk_color(short color_pair); * * int slk_wset(int labnum, const wchar_t *label, int justify); * * int PDC_mouse_in_slk(int y, int x); * void PDC_slk_free(void); * void PDC_slk_initialize(void); * * wchar_t *slk_wlabel(int labnum) * * Description: * These functions manipulate a window that contain Soft Label Keys * (SLK). To use the SLK functions, a call to slk_init() must be * made BEFORE initscr() or newterm(). slk_init() removes 1 or 2 * lines from the useable screen, depending on the format selected. * * The line(s) removed from the screen are used as a separate * window, in which SLKs are displayed. * * slk_init() requires a single parameter which describes the * format of the SLKs as follows: * * 0 3-2-3 format * 1 4-4 format * 2 4-4-4 format (ncurses extension) * 3 4-4-4 format with index line (ncurses extension) * 2 lines used * 55 5-5 format (pdcurses format) * * slk_refresh(), slk_noutrefresh() and slk_touch() are analogous * to refresh(), noutrefresh() and touch(). * * Return Value: * All functions return OK on success and ERR on error. * * Portability X/Open BSD SYS V * slk_init Y - Y * slk_set Y - Y * slk_refresh Y - Y * slk_noutrefresh Y - Y * slk_label Y - Y * slk_clear Y - Y * slk_restore Y - Y * slk_touch Y - Y * slk_attron Y - Y * slk_attrset Y - Y * slk_attroff Y - Y * slk_attr_on Y * slk_attr_set Y * slk_attr_off Y * slk_wset Y * PDC_mouse_in_slk - - - * PDC_slk_free - - - * PDC_slk_initialize - - - * slk_wlabel - - - */ /**************************************************************************** * Included Files ****************************************************************************/ #include #include "curspriv.h" /**************************************************************************** * Private Types ****************************************************************************/ enum { LABEL_NORMAL = 8, LABEL_EXTENDED = 10, LABEL_NCURSES_EXTENDED = 12 }; /**************************************************************************** * Private Data ****************************************************************************/ #ifndef CONFIG_PDCURSES_MULTITHREAD static int label_length = 0; static int labels = 0; static int label_fmt = 0; static int label_line = 0; static bool hidden = false; static struct SLK *slk = (struct SLK *)NULL; #endif /**************************************************************************** * Public Functions ****************************************************************************/ /* slk_init() is the slk initialization routine. * This must be called before initscr(). * * label_fmt = 0, 1 or 55. * 0 = 3-2-3 format * 1 = 4 - 4 format * 2 = 4-4-4 format (ncurses extension for PC 12 function keys) * 3 = 4-4-4 format (ncurses extension for PC 12 function keys - * with index line) * 55 = 5 - 5 format (extended for PC, 10 function keys) */ int slk_init(int fmt) { #ifdef CONFIG_PDCURSES_MULTITHREAD FAR struct pdc_context_s *ctx = PDC_ctx(); #endif PDC_LOG(("slk_init() - called\n")); if (SP) { return ERR; } switch (fmt) { case 0: /* 3 - 2 - 3 */ labels = LABEL_NORMAL; break; case 1: /* 4 - 4 */ labels = LABEL_NORMAL; break; case 2: /* 4 4 4 */ labels = LABEL_NCURSES_EXTENDED; break; case 3: /* 4 4 4 with index */ labels = LABEL_NCURSES_EXTENDED; break; case 55: /* 5 - 5 */ labels = LABEL_EXTENDED; break; default: return ERR; } label_fmt = fmt; slk = calloc(labels, sizeof(struct SLK)); if (!slk) { labels = 0; } return slk ? OK : ERR; } /* Draw a single button */ static void _drawone(int num) { int col; int slen; int i; #ifdef CONFIG_PDCURSES_MULTITHREAD FAR struct pdc_context_s *ctx = PDC_ctx(); #endif if (hidden) { return; } slen = slk[num].len; switch (slk[num].format) { case 0: /* LEFT */ col = 0; break; case 1: /* CENTER */ col = (label_length - slen) / 2; if (col + slen > label_length) { --col; } break; default: /* RIGHT */ col = label_length - slen; break; } wmove(SP->slk_winptr, label_line, slk[num].start_col); for (i = 0; i < label_length; ++i) { waddch(SP->slk_winptr, (i >= col && i < (col + slen)) ? slk[num].label[i - col] : ' '); } } /* Redraw each button */ static void _redraw(void) { #ifdef CONFIG_PDCURSES_MULTITHREAD FAR struct pdc_context_s *ctx = PDC_ctx(); #endif int i; for (i = 0; i < labels; ++i) { _drawone(i); } } /* slk_set() Used to set a slk label to a string. * * labnum = 1 - 8 (or 10) (number of the label) * label = string (8 or 7 bytes total), or NULL * justify = 0 : left, 1 : center, 2 : right */ int slk_set(int labnum, const char *label, int justify) { #ifdef CONFIG_PDCURSES_WIDE wchar_t wlabel[32]; PDC_mbstowcs(wlabel, label, 31); return slk_wset(labnum, wlabel, justify); #else #ifdef CONFIG_PDCURSES_MULTITHREAD FAR struct pdc_context_s *ctx = PDC_ctx(); #endif PDC_LOG(("slk_set() - called\n")); if (labnum < 1 || labnum > labels || justify < 0 || justify > 2) { return ERR; } labnum--; if (!label || !(*label)) { /* Clear the label */ *slk[labnum].label = 0; slk[labnum].format = 0; slk[labnum].len = 0; } else { int i; int j = 0; /* Skip leading spaces */ while (label[j] == ' ') { j++; } /* Copy it */ for (i = 0; i < label_length; i++) { chtype ch = label[i + j]; slk[labnum].label[i] = ch; if (!ch) { break; } } /* Drop trailing spaces */ while ((i + j) && (label[i + j - 1] == ' ')) { i--; } slk[labnum].label[i] = 0; slk[labnum].format = justify; slk[labnum].len = i; } _drawone(labnum); return OK; #endif } int slk_refresh(void) { PDC_LOG(("slk_refresh() - called\n")); return (slk_noutrefresh() == ERR) ? ERR : doupdate(); } int slk_noutrefresh(void) { #ifdef CONFIG_PDCURSES_MULTITHREAD FAR struct pdc_context_s *ctx = PDC_ctx(); #endif PDC_LOG(("slk_noutrefresh() - called\n")); return wnoutrefresh(SP->slk_winptr); } char *slk_label(int labnum) { #ifdef CONFIG_PDCURSES_MULTITHREAD FAR struct pdc_context_s *ctx = PDC_ctx(); #else static char slk_temp2[33]; #endif #ifdef CONFIG_PDCURSES_WIDE wchar_t *wtemp = slk_wlabel(labnum); PDC_wcstombs(temp, wtemp, 32); #else chtype *p; int i; PDC_LOG(("slk_label() - called\n")); if (labnum < 1 || labnum > labels) { return (char *)0; } for (i = 0, p = slk[labnum - 1].label; *p; i++) { slk_temp2[i] = *p++; } slk_temp2[i] = '\0'; #endif return slk_temp2; } int slk_clear(void) { #ifdef CONFIG_PDCURSES_MULTITHREAD FAR struct pdc_context_s *ctx = PDC_ctx(); #endif PDC_LOG(("slk_clear() - called\n")); hidden = true; werase(SP->slk_winptr); return wrefresh(SP->slk_winptr); } int slk_restore(void) { #ifdef CONFIG_PDCURSES_MULTITHREAD FAR struct pdc_context_s *ctx = PDC_ctx(); #endif PDC_LOG(("slk_restore() - called\n")); hidden = false; _redraw(); return wrefresh(SP->slk_winptr); } int slk_touch(void) { #ifdef CONFIG_PDCURSES_MULTITHREAD FAR struct pdc_context_s *ctx = PDC_ctx(); #endif PDC_LOG(("slk_touch() - called\n")); return touchwin(SP->slk_winptr); } int slk_attron(const chtype attrs) { int rc; #ifdef CONFIG_PDCURSES_MULTITHREAD FAR struct pdc_context_s *ctx = PDC_ctx(); #endif PDC_LOG(("slk_attron() - called\n")); rc = wattron(SP->slk_winptr, attrs); _redraw(); return rc; } int slk_attr_on(const attr_t attrs, void *opts) { PDC_LOG(("slk_attr_on() - called\n")); return slk_attron(attrs); } int slk_attroff(const chtype attrs) { int rc; #ifdef CONFIG_PDCURSES_MULTITHREAD FAR struct pdc_context_s *ctx = PDC_ctx(); #endif PDC_LOG(("slk_attroff() - called\n")); rc = wattroff(SP->slk_winptr, attrs); _redraw(); return rc; } int slk_attr_off(const attr_t attrs, void *opts) { PDC_LOG(("slk_attr_off() - called\n")); return slk_attroff(attrs); } int slk_attrset(const chtype attrs) { int rc; #ifdef CONFIG_PDCURSES_MULTITHREAD FAR struct pdc_context_s *ctx = PDC_ctx(); #endif PDC_LOG(("slk_attrset() - called\n")); rc = wattrset(SP->slk_winptr, attrs); _redraw(); return rc; } int slk_color(short color_pair) { int rc; #ifdef CONFIG_PDCURSES_MULTITHREAD FAR struct pdc_context_s *ctx = PDC_ctx(); #endif PDC_LOG(("slk_color() - called\n")); rc = wcolor_set(SP->slk_winptr, color_pair, NULL); _redraw(); return rc; } int slk_attr_set(const attr_t attrs, short color_pair, void *opts) { PDC_LOG(("slk_attr_set() - called\n")); return slk_attrset(attrs | COLOR_PAIR(color_pair)); } static void _slk_calc(void) { int i, center, col = 0; #ifdef CONFIG_PDCURSES_MULTITHREAD FAR struct pdc_context_s *ctx = PDC_ctx(); #endif label_length = COLS / labels; if (label_length > 31) { label_length = 31; } switch (label_fmt) { case 0: /* 3 - 2 - 3 F-Key layout */ --label_length; slk[0].start_col = col; slk[1].start_col = (col += label_length); slk[2].start_col = (col += label_length); center = COLS / 2; slk[3].start_col = center - label_length + 1; slk[4].start_col = center + 1; col = COLS - (label_length * 3) + 1; slk[5].start_col = col; slk[6].start_col = (col += label_length); slk[7].start_col = (col += label_length); break; case 1: /* 4 - 4 F-Key layout */ for (i = 0; i < 8; i++) { slk[i].start_col = col; col += label_length; if (i == 3) { col = COLS - (label_length * 4) + 1; } } break; case 2: /* 4 4 4 F-Key layout */ case 3: /* 4 4 4 F-Key layout with index */ for (i = 0; i < 4; i++) { slk[i].start_col = col; col += label_length; } center = COLS / 2; slk[4].start_col = center - (label_length * 2) + 1; slk[5].start_col = center - label_length - 1; slk[6].start_col = center + 1; slk[7].start_col = center + label_length + 1; col = COLS - (label_length * 4) + 1; for (i = 8; i < 12; i++) { slk[i].start_col = col; col += label_length; } break; default: /* 5 - 5 F-Key layout */ for (i = 0; i < 10; i++) { slk[i].start_col = col; col += label_length; if (i == 4) { col = COLS - (label_length * 5) + 1; } } } --label_length; /* make sure labels are all in window */ _redraw(); } void PDC_slk_initialize(void) { #ifdef CONFIG_PDCURSES_MULTITHREAD FAR struct pdc_context_s *ctx = PDC_ctx(); #endif if (slk) { if (label_fmt == 3) { SP->slklines = 2; label_line = 1; } else { SP->slklines = 1; } if (!SP->slk_winptr) { if (!(SP->slk_winptr = newwin(SP->slklines, COLS, LINES - SP->slklines, 0))) { return; } wattrset(SP->slk_winptr, A_REVERSE); } _slk_calc(); /* If we have an index line, display it now */ if (label_fmt == 3) { chtype save_attr; int i; save_attr = SP->slk_winptr->_attrs; wattrset(SP->slk_winptr, A_NORMAL); wmove(SP->slk_winptr, 0, 0); whline(SP->slk_winptr, 0, COLS); for (i = 0; i < labels; i++) { mvwprintw(SP->slk_winptr, 0, slk[i].start_col, "F%d", i + 1); } SP->slk_winptr->_attrs = save_attr; } touchwin(SP->slk_winptr); } } void PDC_slk_free(void) { #ifdef CONFIG_PDCURSES_MULTITHREAD FAR struct pdc_context_s *ctx = PDC_ctx(); #endif if (slk) { if (SP->slk_winptr) { delwin(SP->slk_winptr); SP->slk_winptr = (WINDOW *) NULL; } free(slk); slk = (struct SLK *)NULL; label_length = 0; labels = 0; label_fmt = 0; label_line = 0; hidden = false; } } int PDC_mouse_in_slk(int y, int x) { int i; #ifdef CONFIG_PDCURSES_MULTITHREAD FAR struct pdc_context_s *ctx = PDC_ctx(); #endif PDC_LOG(("PDC_mouse_in_slk() - called: y->%d x->%d\n", y, x)); /* If the line on which the mouse was clicked is NOT the last line of the * screen, we are not interested in it. */ if (!slk || !SP->slk_winptr || (y != SP->slk_winptr->_begy + label_line)) { return 0; } for (i = 0; i < labels; i++) { if (x >= slk[i].start_col && x < (slk[i].start_col + label_length)) { return i + 1; } } return 0; } #ifdef CONFIG_PDCURSES_WIDE int slk_wset(int labnum, const wchar_t *label, int justify) { #ifdef CONFIG_PDCURSES_MULTITHREAD FAR struct pdc_context_s *ctx = PDC_ctx(); #endif PDC_LOG(("slk_wset() - called\n")); if (labnum < 1 || labnum > labels || justify < 0 || justify > 2) { return ERR; } labnum--; if (!label || !(*label)) { /* Clear the label */ *slk[labnum].label = 0; slk[labnum].format = 0; slk[labnum].len = 0; } else { int i, j = 0; /* Skip leading spaces */ while (label[j] == L' ') { j++; } /* Copy it */ for (i = 0; i < label_length; i++) { chtype ch = label[i + j]; slk[labnum].label[i] = ch; if (!ch) { break; } } /* Drop trailing spaces */ while ((i + j) && (label[i + j - 1] == L' ')) { i--; } slk[labnum].label[i] = 0; slk[labnum].format = justify; slk[labnum].len = i; } _drawone(labnum); return OK; } wchar_t *slk_wlabel(int labnum) { #ifdef CONFIG_PDCURSES_MULTITHREAD FAR struct pdc_context_s *ctx = PDC_ctx(); #else static wchar_t slk_temp[33]; #endif chtype *p; int i; PDC_LOG(("slk_wlabel() - called\n")); if (labnum < 1 || labnum > labels) { return (wchar_t *) 0; } for (i = 0, p = slk[labnum - 1].label; *p; i++) { slk_temp[i] = *p++; } slk_temp[i] = '\0'; return slk_temp; } #endif