|  | /**************************************************************************** | 
|  | * apps/graphics/pdcurses/pdc_border.c | 
|  | * Public Domain Curses | 
|  | * RCSID("$Id: border.c,v 1.53 2008/07/13 16:08:18 wmcbrine Exp $") | 
|  | * | 
|  | *   Copyright (C) 2017 Gregory Nutt. All rights reserved. | 
|  | *   Adapted by: Gregory Nutt <gnutt@nuttx.org> | 
|  | * | 
|  | * 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: border | 
|  | * | 
|  | * Synopsis: | 
|  | *       int border(chtype ls, chtype rs, chtype ts, chtype bs, chtype tl, | 
|  | *                  chtype tr, chtype bl, chtype br); | 
|  | *       int wborder(WINDOW *win, chtype ls, chtype rs, chtype ts, | 
|  | *                   chtype bs, chtype tl, chtype tr, chtype bl, chtype br); | 
|  | *       int box(WINDOW *win, chtype verch, chtype horch); | 
|  | *       int hline(chtype ch, int n); | 
|  | *       int vline(chtype ch, int n); | 
|  | *       int whline(WINDOW *win, chtype ch, int n); | 
|  | *       int wvline(WINDOW *win, chtype ch, int n); | 
|  | *       int mvhline(int y, int x, chtype ch, int n); | 
|  | *       int mvvline(int y, int x, chtype ch, int n); | 
|  | *       int mvwhline(WINDOW *win, int y, int x, chtype ch, int n); | 
|  | *       int mvwvline(WINDOW *win, int y, int x, chtype ch, int n); | 
|  | * | 
|  | *       int border_set(const cchar_t *ls, const cchar_t *rs, | 
|  | *                      const cchar_t *ts, const cchar_t *bs, | 
|  | *                      const cchar_t *tl, const cchar_t *tr, | 
|  | *                      const cchar_t *bl, const cchar_t *br); | 
|  | *       int wborder_set(WINDOW *win, const cchar_t *ls, const cchar_t *rs, | 
|  | *                       const cchar_t *ts, const cchar_t *bs, | 
|  | *                       const cchar_t *tl, const cchar_t *tr, | 
|  | *                       const cchar_t *bl, const cchar_t *br); | 
|  | *       int box_set(WINDOW *win, const cchar_t *verch, const cchar_t *horch); | 
|  | *       int hline_set(const cchar_t *wch, int n); | 
|  | *       int vline_set(const cchar_t *wch, int n); | 
|  | *       int whline_set(WINDOW *win, const cchar_t *wch, int n); | 
|  | *       int wvline_set(WINDOW *win, const cchar_t *wch, int n); | 
|  | *       int mvhline_set(int y, int x, const cchar_t *wch, int n); | 
|  | *       int mvvline_set(int y, int x, const cchar_t *wch, int n); | 
|  | *       int mvwhline_set(WINDOW *win, int y, int x, const cchar_t *wch, int n); | 
|  | *       int mvwvline_set(WINDOW *win, int y, int x, const cchar_t *wch, int n); | 
|  | * | 
|  | * Description: | 
|  | *       border(), wborder(), and box() draw a border around the edge of | 
|  | *       the window. If any argument is zero, an appropriate default is | 
|  | *       used: | 
|  | * | 
|  | *               ls      left side of border             ACS_VLINE | 
|  | *               rs      right side of border            ACS_VLINE | 
|  | *               ts      top side of border              ACS_HLINE | 
|  | *               bs      bottom side of border           ACS_HLINE | 
|  | *               tl      top left corner of border       ACS_ULCORNER | 
|  | *               tr      top right corner of border      ACS_URCORNER | 
|  | *               bl      bottom left corner of border    ACS_LLCORNER | 
|  | *               br      bottom right corner of border   ACS_LRCORNER | 
|  | * | 
|  | *       hline() and whline() draw a horizontal line, using ch, starting | 
|  | *       from the current cursor position. The cursor position does not | 
|  | *       change. The line is at most n characters long, or as many as | 
|  | *       will fit in the window. | 
|  | * | 
|  | *       vline() and wvline() draw a vertical line, using ch, starting | 
|  | *       from the current cursor position. The cursor position does not | 
|  | *       change. The line is at most n characters long, or as many as | 
|  | *       will fit in the window. | 
|  | * | 
|  | * Return Value: | 
|  | *       These functions return OK on success and ERR on error. | 
|  | * | 
|  | * Portability                                X/Open    BSD    SYS V | 
|  | *       border                                  Y       -      4.0 | 
|  | *       wborder                                 Y       -      4.0 | 
|  | *       box                                     Y       Y       Y | 
|  | *       hline                                   Y       -      4.0 | 
|  | *       vline                                   Y       -      4.0 | 
|  | *       whline                                  Y       -      4.0 | 
|  | *       wvline                                  Y       -      4.0 | 
|  | *       mvhline                                 Y | 
|  | *       mvvline                                 Y | 
|  | *       mvwhline                                Y | 
|  | *       mvwvline                                Y | 
|  | *       border_set                              Y | 
|  | *       wborder_set                             Y | 
|  | *       box_set                                 Y | 
|  | *       hline_set                               Y | 
|  | *       vline_set                               Y | 
|  | *       whline_set                              Y | 
|  | *       wvline_set                              Y | 
|  | *       mvhline_set                             Y | 
|  | *       mvvline_set                             Y | 
|  | *       mvwhline_set                            Y | 
|  | *       mvwvline_set                            Y | 
|  | */ | 
|  |  | 
|  | /**************************************************************************** | 
|  | * Included Files | 
|  | ****************************************************************************/ | 
|  |  | 
|  | #include "curspriv.h" | 
|  |  | 
|  | /**************************************************************************** | 
|  | * Private Functions | 
|  | ****************************************************************************/ | 
|  |  | 
|  | /* _attr_passthru() -- Takes a single chtype 'ch' and checks if the | 
|  | *  current attribute of window 'win', as set by wattrset(), and/or the | 
|  | *  current background of win, as set by wbkgd(), should by combined with | 
|  | *  it. Attributes set explicitly in ch take precedence. | 
|  | */ | 
|  |  | 
|  | static chtype _attr_passthru(WINDOW *win, chtype ch) | 
|  | { | 
|  | chtype attr; | 
|  |  | 
|  | /* If the incoming character doesn't have its own attribute, then use the | 
|  | * current attributes for the window. If the incoming character has | 
|  | * attributes, but not a color component, OR the attributes to the current | 
|  | * attributes for the window. If the incoming character has a color | 
|  | * component, use only the attributes from the incoming character. | 
|  | */ | 
|  |  | 
|  | attr = ch & A_ATTRIBUTES; | 
|  | if (!(attr & A_COLOR)) | 
|  | { | 
|  | attr |= win->_attrs; | 
|  | } | 
|  |  | 
|  | /* wrs (4/10/93) -- Apply the same sort of logic for the window background, | 
|  | * in that it only takes precedence if other color attributes are not there. | 
|  | */ | 
|  |  | 
|  | if (!(attr & A_COLOR)) | 
|  | { | 
|  | attr |= win->_bkgd & A_ATTRIBUTES; | 
|  | } | 
|  | else | 
|  | { | 
|  | attr |= win->_bkgd & (A_ATTRIBUTES ^ A_COLOR); | 
|  | } | 
|  |  | 
|  | ch = (ch & A_CHARTEXT) | attr; | 
|  |  | 
|  | return ch; | 
|  | } | 
|  |  | 
|  | /**************************************************************************** | 
|  | * Public Functions | 
|  | ****************************************************************************/ | 
|  |  | 
|  | int wborder(WINDOW *win, chtype ls, chtype rs, chtype ts, chtype bs, | 
|  | chtype tl, chtype tr, chtype bl, chtype br) | 
|  | { | 
|  | int xmax; | 
|  | int ymax; | 
|  | int i; | 
|  |  | 
|  | PDC_LOG(("wborder() - called\n")); | 
|  |  | 
|  | if (!win) | 
|  | { | 
|  | return ERR; | 
|  | } | 
|  |  | 
|  | ymax = win->_maxy - 1; | 
|  | xmax = win->_maxx - 1; | 
|  |  | 
|  | ls = _attr_passthru(win, ls ? ls : ACS_VLINE); | 
|  | rs = _attr_passthru(win, rs ? rs : ACS_VLINE); | 
|  | ts = _attr_passthru(win, ts ? ts : ACS_HLINE); | 
|  | bs = _attr_passthru(win, bs ? bs : ACS_HLINE); | 
|  | tl = _attr_passthru(win, tl ? tl : ACS_ULCORNER); | 
|  | tr = _attr_passthru(win, tr ? tr : ACS_URCORNER); | 
|  | bl = _attr_passthru(win, bl ? bl : ACS_LLCORNER); | 
|  | br = _attr_passthru(win, br ? br : ACS_LRCORNER); | 
|  |  | 
|  | for (i = 1; i < xmax; i++) | 
|  | { | 
|  | win->_y[0][i]    = ts; | 
|  | win->_y[ymax][i] = bs; | 
|  | } | 
|  |  | 
|  | for (i = 1; i < ymax; i++) | 
|  | { | 
|  | win->_y[i][0]    = ls; | 
|  | win->_y[i][xmax] = rs; | 
|  | } | 
|  |  | 
|  | win->_y[0][0]        = tl; | 
|  | win->_y[0][xmax]     = tr; | 
|  | win->_y[ymax][0]     = bl; | 
|  | win->_y[ymax][xmax]  = br; | 
|  |  | 
|  | for (i = 0; i <= ymax; i++) | 
|  | { | 
|  | win->_firstch[i] = 0; | 
|  | win->_lastch[i]  = xmax; | 
|  | } | 
|  |  | 
|  | PDC_sync(win); | 
|  |  | 
|  | return OK; | 
|  | } | 
|  |  | 
|  | int border(chtype ls, chtype rs, chtype ts, chtype bs, chtype tl, | 
|  | chtype tr, chtype bl, chtype br) | 
|  | { | 
|  | #ifdef CONFIG_PDCURSES_MULTITHREAD | 
|  | FAR struct pdc_context_s *ctx = PDC_ctx(); | 
|  | #endif | 
|  | PDC_LOG(("border() - called\n")); | 
|  |  | 
|  | return wborder(stdscr, ls, rs, ts, bs, tl, tr, bl, br); | 
|  | } | 
|  |  | 
|  | int box(WINDOW *win, chtype verch, chtype horch) | 
|  | { | 
|  | PDC_LOG(("box() - called\n")); | 
|  |  | 
|  | return wborder(win, verch, verch, horch, horch, 0, 0, 0, 0); | 
|  | } | 
|  |  | 
|  | int whline(WINDOW *win, chtype ch, int n) | 
|  | { | 
|  | chtype *dest; | 
|  | int startpos, endpos; | 
|  |  | 
|  | PDC_LOG(("whline() - called\n")); | 
|  |  | 
|  | if (!win || n < 1) | 
|  | { | 
|  | return ERR; | 
|  | } | 
|  |  | 
|  | startpos = win->_curx; | 
|  | endpos = min(startpos + n, win->_maxx) - 1; | 
|  | dest = win->_y[win->_cury]; | 
|  | ch = _attr_passthru(win, ch ? ch : ACS_HLINE); | 
|  |  | 
|  | for (n = startpos; n <= endpos; n++) | 
|  | { | 
|  | dest[n] = ch; | 
|  | } | 
|  |  | 
|  | n = win->_cury; | 
|  |  | 
|  | if (startpos < win->_firstch[n] || win->_firstch[n] == _NO_CHANGE) | 
|  | { | 
|  | win->_firstch[n] = startpos; | 
|  | } | 
|  |  | 
|  | if (endpos > win->_lastch[n]) | 
|  | { | 
|  | win->_lastch[n] = endpos; | 
|  | } | 
|  |  | 
|  | PDC_sync(win); | 
|  |  | 
|  | return OK; | 
|  | } | 
|  |  | 
|  | int hline(chtype ch, int n) | 
|  | { | 
|  | #ifdef CONFIG_PDCURSES_MULTITHREAD | 
|  | FAR struct pdc_context_s *ctx = PDC_ctx(); | 
|  | #endif | 
|  | PDC_LOG(("hline() - called\n")); | 
|  |  | 
|  | return whline(stdscr, ch, n); | 
|  | } | 
|  |  | 
|  | int mvhline(int y, int x, chtype ch, int n) | 
|  | { | 
|  | #ifdef CONFIG_PDCURSES_MULTITHREAD | 
|  | FAR struct pdc_context_s *ctx = PDC_ctx(); | 
|  | #endif | 
|  | PDC_LOG(("mvhline() - called\n")); | 
|  |  | 
|  | if (move(y, x) == ERR) | 
|  | { | 
|  | return ERR; | 
|  | } | 
|  |  | 
|  | return whline(stdscr, ch, n); | 
|  | } | 
|  |  | 
|  | int mvwhline(WINDOW *win, int y, int x, chtype ch, int n) | 
|  | { | 
|  | PDC_LOG(("mvwhline() - called\n")); | 
|  |  | 
|  | if (wmove(win, y, x) == ERR) | 
|  | { | 
|  | return ERR; | 
|  | } | 
|  |  | 
|  | return whline(win, ch, n); | 
|  | } | 
|  |  | 
|  | int wvline(WINDOW *win, chtype ch, int n) | 
|  | { | 
|  | int endpos; | 
|  | int x; | 
|  |  | 
|  | PDC_LOG(("wvline() - called\n")); | 
|  |  | 
|  | if (!win || n < 1) | 
|  | { | 
|  | return ERR; | 
|  | } | 
|  |  | 
|  | endpos = min(win->_cury + n, win->_maxy); | 
|  | x = win->_curx; | 
|  |  | 
|  | ch = _attr_passthru(win, ch ? ch : ACS_VLINE); | 
|  |  | 
|  | for (n = win->_cury; n < endpos; n++) | 
|  | { | 
|  | win->_y[n][x] = ch; | 
|  |  | 
|  | if (x < win->_firstch[n] || win->_firstch[n] == _NO_CHANGE) | 
|  | { | 
|  | win->_firstch[n] = x; | 
|  | } | 
|  |  | 
|  | if (x > win->_lastch[n]) | 
|  | { | 
|  | win->_lastch[n] = x; | 
|  | } | 
|  | } | 
|  |  | 
|  | PDC_sync(win); | 
|  |  | 
|  | return OK; | 
|  | } | 
|  |  | 
|  | int vline(chtype ch, int n) | 
|  | { | 
|  | #ifdef CONFIG_PDCURSES_MULTITHREAD | 
|  | FAR struct pdc_context_s *ctx = PDC_ctx(); | 
|  | #endif | 
|  | PDC_LOG(("vline() - called\n")); | 
|  |  | 
|  | return wvline(stdscr, ch, n); | 
|  | } | 
|  |  | 
|  | int mvvline(int y, int x, chtype ch, int n) | 
|  | { | 
|  | #ifdef CONFIG_PDCURSES_MULTITHREAD | 
|  | FAR struct pdc_context_s *ctx = PDC_ctx(); | 
|  | #endif | 
|  | PDC_LOG(("mvvline() - called\n")); | 
|  |  | 
|  | if (move(y, x) == ERR) | 
|  | { | 
|  | return ERR; | 
|  | } | 
|  |  | 
|  | return wvline(stdscr, ch, n); | 
|  | } | 
|  |  | 
|  | int mvwvline(WINDOW *win, int y, int x, chtype ch, int n) | 
|  | { | 
|  | PDC_LOG(("mvwvline() - called\n")); | 
|  |  | 
|  | if (wmove(win, y, x) == ERR) | 
|  | { | 
|  | return ERR; | 
|  | } | 
|  |  | 
|  | return wvline(win, ch, n); | 
|  | } | 
|  |  | 
|  | #ifdef CONFIG_PDCURSES_WIDE | 
|  | int wborder_set(WINDOW *win, const cchar_t *ls, const cchar_t *rs, | 
|  | const cchar_t *ts, const cchar_t *bs, const cchar_t *tl, | 
|  | const cchar_t *tr, const cchar_t *bl, const cchar_t *br) | 
|  | { | 
|  | PDC_LOG(("wborder_set() - called\n")); | 
|  |  | 
|  | return wborder(win, ls ? *ls : 0, rs ? *rs : 0, ts ? *ts : 0, | 
|  | bs ? *bs : 0, tl ? *tl : 0, tr ? *tr : 0, | 
|  | bl ? *bl : 0, br ? *br : 0); | 
|  | } | 
|  |  | 
|  | int border_set(const cchar_t *ls, const cchar_t *rs, const cchar_t *ts, | 
|  | const cchar_t *bs, const cchar_t *tl, const cchar_t *tr, | 
|  | const cchar_t *bl, const cchar_t *br) | 
|  | { | 
|  | #ifdef CONFIG_PDCURSES_MULTITHREAD | 
|  | FAR struct pdc_context_s *ctx = PDC_ctx(); | 
|  | #endif | 
|  | PDC_LOG(("border_set() - called\n")); | 
|  |  | 
|  | return wborder_set(stdscr, ls, rs, ts, bs, tl, tr, bl, br); | 
|  | } | 
|  |  | 
|  | int box_set(WINDOW *win, const cchar_t *verch, const cchar_t *horch) | 
|  | { | 
|  | PDC_LOG(("box_set() - called\n")); | 
|  |  | 
|  | return wborder_set(win, verch, verch, horch, horch, | 
|  | (const cchar_t *)NULL, (const cchar_t *)NULL, | 
|  | (const cchar_t *)NULL, (const cchar_t *)NULL); | 
|  | } | 
|  |  | 
|  | int whline_set(WINDOW *win, const cchar_t *wch, int n) | 
|  | { | 
|  | PDC_LOG(("whline_set() - called\n")); | 
|  |  | 
|  | return wch ? whline(win, *wch, n) : ERR; | 
|  | } | 
|  |  | 
|  | int hline_set(const cchar_t *wch, int n) | 
|  | { | 
|  | #ifdef CONFIG_PDCURSES_MULTITHREAD | 
|  | FAR struct pdc_context_s *ctx = PDC_ctx(); | 
|  | #endif | 
|  | PDC_LOG(("hline_set() - called\n")); | 
|  |  | 
|  | return whline_set(stdscr, wch, n); | 
|  | } | 
|  |  | 
|  | int mvhline_set(int y, int x, const cchar_t *wch, int n) | 
|  | { | 
|  | #ifdef CONFIG_PDCURSES_MULTITHREAD | 
|  | FAR struct pdc_context_s *ctx = PDC_ctx(); | 
|  | #endif | 
|  | PDC_LOG(("mvhline_set() - called\n")); | 
|  |  | 
|  | if (move(y, x) == ERR) | 
|  | { | 
|  | return ERR; | 
|  | } | 
|  |  | 
|  | return whline_set(stdscr, wch, n); | 
|  | } | 
|  |  | 
|  | int mvwhline_set(WINDOW *win, int y, int x, const cchar_t *wch, int n) | 
|  | { | 
|  | PDC_LOG(("mvwhline_set() - called\n")); | 
|  |  | 
|  | if (wmove(win, y, x) == ERR) | 
|  | { | 
|  | return ERR; | 
|  | } | 
|  |  | 
|  | return whline_set(win, wch, n); | 
|  | } | 
|  |  | 
|  | int wvline_set(WINDOW *win, const cchar_t *wch, int n) | 
|  | { | 
|  | PDC_LOG(("wvline_set() - called\n")); | 
|  |  | 
|  | return wch ? wvline(win, *wch, n) : ERR; | 
|  | } | 
|  |  | 
|  | int vline_set(const cchar_t *wch, int n) | 
|  | { | 
|  | #ifdef CONFIG_PDCURSES_MULTITHREAD | 
|  | FAR struct pdc_context_s *ctx = PDC_ctx(); | 
|  | #endif | 
|  | PDC_LOG(("vline_set() - called\n")); | 
|  |  | 
|  | return wvline_set(stdscr, wch, n); | 
|  | } | 
|  |  | 
|  | int mvvline_set(int y, int x, const cchar_t *wch, int n) | 
|  | { | 
|  | #ifdef CONFIG_PDCURSES_MULTITHREAD | 
|  | FAR struct pdc_context_s *ctx = PDC_ctx(); | 
|  | #endif | 
|  | PDC_LOG(("mvvline_set() - called\n")); | 
|  |  | 
|  | if (move(y, x) == ERR) | 
|  | { | 
|  | return ERR; | 
|  | } | 
|  |  | 
|  | return wvline_set(stdscr, wch, n); | 
|  | } | 
|  |  | 
|  | int mvwvline_set(WINDOW *win, int y, int x, const cchar_t *wch, int n) | 
|  | { | 
|  | PDC_LOG(("mvwvline_set() - called\n")); | 
|  |  | 
|  | if (wmove(win, y, x) == ERR) | 
|  | { | 
|  | return ERR; | 
|  | } | 
|  |  | 
|  | return wvline_set(win, wch, n); | 
|  | } | 
|  | #endif |