text: /****************************************************************************
   * 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
  