]> ncurses.scripts.mit.edu Git - ncurses.git/blobdiff - form/frm_driver.c
ncurses 6.0 - patch 20170909
[ncurses.git] / form / frm_driver.c
index ed561bf1e9e57e91257a91f6d0159599dc243021..837b02a1b6d49f37679432c49f08446e11b8f3ae 100644 (file)
@@ -1,5 +1,5 @@
 /****************************************************************************
- * Copyright (c) 1998-2013,2014 Free Software Foundation, Inc.              *
+ * Copyright (c) 1998-2016,2017 Free Software Foundation, Inc.              *
  *                                                                          *
  * Permission is hereby granted, free of charge, to any person obtaining a  *
  * copy of this software and associated documentation files (the            *
@@ -32,7 +32,7 @@
 
 #include "form.priv.h"
 
-MODULE_ID("$Id: frm_driver.c,v 1.110 2014/02/10 00:42:48 tom Exp $")
+MODULE_ID("$Id: frm_driver.c,v 1.123 2017/09/09 22:35:49 tom Exp $")
 
 /*----------------------------------------------------------------------------
   This is the core module of the form library. It contains the majority
@@ -99,9 +99,9 @@ Perhaps at some time we will make this configurable at runtime.
 #define GROW_IF_NAVIGATE (1)
 
 #if USE_WIDEC_SUPPORT
-#define myADDNSTR(w, s, n) wadd_wchnstr(w, s, n)
-#define myINSNSTR(w, s, n) wins_wchnstr(w, s, n)
-#define myINNSTR(w, s, n)  fix_wchnstr(w, s, n)
+#define myADDNSTR(w, s, n) wide_waddnstr(w, s, n)
+#define myINSNSTR(w, s, n) wide_winsnstr(w, s, n)
+#define myINNSTR(w, s, n)  wide_winnstr(w, s, n)
 #define myWCWIDTH(w, y, x) cell_width(w, y, x)
 #else
 #define myADDNSTR(w, s, n) waddnstr(w, s, n)
@@ -172,15 +172,16 @@ static int FE_Delete_Previous(FORM *);
    instead of a derived window because it contains invisible parts.
    This is true for non-public fields and for scrollable fields. */
 #define Has_Invisible_Parts(field)     \
-  (!((unsigned)(field)->opts & O_PUBLIC) || \
+  (!(Field_Has_Option(field, O_PUBLIC)) || \
    Is_Scroll_Field(field))
 
 /* Logic to decide whether or not a field needs justification */
 #define Justification_Allowed(field)        \
    (((field)->just != NO_JUSTIFICATION)  && \
     (Single_Line_Field(field))           && \
-    (((field)->dcols == (field)->cols)   && \
-    ((unsigned)(field)->opts & O_STATIC)))
+    ((Field_Has_Option(field, O_STATIC)  && \
+     ((field)->dcols == (field)->cols))  || \
+    Field_Has_Option(field, O_DYNAMIC_JUSTIFY)))
 
 /* Logic to determine whether or not a dynamic field may still grow */
 #define Growable(field) ((field)->status & _MAY_GROW)
@@ -194,7 +195,7 @@ static int FE_Delete_Previous(FORM *);
 #define Field_Really_Appears(field)         \
   ((field->form)                          &&\
    (field->form->status & _POSTED)        &&\
-   ((unsigned)field->opts & O_VISIBLE)    &&\
+   (Field_Has_Option(field, O_VISIBLE))   &&\
    (field->page == field->form->curpage))
 
 /* Logic to determine whether or not we are on the first position in the
@@ -238,9 +239,29 @@ check_pos(FORM *form, int lineno)
   Wide-character special functions
   --------------------------------------------------------------------------*/
 #if USE_WIDEC_SUPPORT
-/* like winsnstr */
+/* add like waddnstr, but using cchar_t* rather than char*
+ */
+static int
+wide_waddnstr(WINDOW *w, const cchar_t *s, int n)
+{
+  int rc = OK;
+
+  while (n-- > 0)
+    {
+      if ((rc = wadd_wch(w, s)) != OK)
+       break;
+      ++s;
+    }
+  return rc;
+}
+
+/* insert like winsnstr, but using cchar_t* rather than char*
+ *
+ * X/Open Curses has no close equivalent; inserts are done only with wchar_t
+ * strings.
+ */
 static int
-wins_wchnstr(WINDOW *w, cchar_t *s, int n)
+wide_winsnstr(WINDOW *w, const cchar_t *s, int n)
 {
   int code = ERR;
   int y, x;
@@ -256,11 +277,13 @@ wins_wchnstr(WINDOW *w, cchar_t *s, int n)
   return code;
 }
 
-/* win_wchnstr is inconsistent with winnstr, since it returns OK rather than
- * the number of items transferred.
+/* retrieve like winnstr, but using cchar_t*, rather than char*.
+ *
+ * X/Open Curses' closest equivalent, win_wchnstr(), is inconsistent with
+ * winnstr(), since it returns OK rather than the number of items transferred.
  */
 static int
-fix_wchnstr(WINDOW *w, cchar_t *s, int n)
+wide_winnstr(WINDOW *w, cchar_t *s, int n)
 {
   int x;
 
@@ -860,7 +883,7 @@ _nc_Refresh_Current_Field(FORM *form)
   field = form->current;
   formwin = Get_Form_Window(form);
 
-  if ((unsigned)field->opts & O_PUBLIC)
+  if (Field_Has_Option(field, O_PUBLIC))
     {
       if (Is_Scroll_Field(field))
        {
@@ -978,26 +1001,29 @@ Perform_Justification(FIELD *field, WINDOW *win)
   int len;
   int col = 0;
 
-  bp = Get_Start_Of_Data(field->buf, Buffer_Length(field));
+  bp = (Field_Has_Option(field, O_NO_LEFT_STRIP)
+       ? field->buf
+       : Get_Start_Of_Data(field->buf, Buffer_Length(field)));
   len = (int)(After_End_Of_Data(field->buf, Buffer_Length(field)) - bp);
 
   if (len > 0)
     {
-      assert(win && (field->drows == 1) && (field->dcols == field->cols));
+      assert(win && (field->drows == 1));
 
-      switch (field->just)
-       {
-       case JUSTIFY_LEFT:
-         break;
-       case JUSTIFY_CENTER:
-         col = (field->cols - len) / 2;
-         break;
-       case JUSTIFY_RIGHT:
-         col = field->cols - len;
-         break;
-       default:
-         break;
-       }
+      if (field->cols - len >= 0)
+       switch (field->just)
+         {
+         case JUSTIFY_LEFT:
+           break;
+         case JUSTIFY_CENTER:
+           col = (field->cols - len) / 2;
+           break;
+         case JUSTIFY_RIGHT:
+           col = field->cols - len;
+           break;
+         default:
+           break;
+         }
 
       wmove(win, 0, col);
       myADDNSTR(win, bp, len);
@@ -1019,9 +1045,14 @@ static void
 Undo_Justification(FIELD *field, WINDOW *win)
 {
   FIELD_CELL *bp;
+  int y, x;
   int len;
 
-  bp = Get_Start_Of_Data(field->buf, Buffer_Length(field));
+  getyx(win, y, x);
+
+  bp = (Field_Has_Option(field, O_NO_LEFT_STRIP)
+       ? field->buf
+       : Get_Start_Of_Data(field->buf, Buffer_Length(field)));
   len = (int)(After_End_Of_Data(field->buf, Buffer_Length(field)) - bp);
 
   if (len > 0)
@@ -1030,6 +1061,7 @@ Undo_Justification(FIELD *field, WINDOW *win)
       wmove(win, 0, 0);
       myADDNSTR(win, bp, len);
     }
+  wmove(win, y, x);
 }
 
 /*---------------------------------------------------------------------------
@@ -1111,7 +1143,7 @@ Display_Or_Erase_Field(FIELD *field, bool bEraseFlag)
     return E_SYSTEM_ERROR;
   else
     {
-      if ((unsigned)field->opts & O_VISIBLE)
+      if (Field_Has_Option(field, O_VISIBLE))
        {
          Set_Field_Window_Attributes(field, win);
        }
@@ -1124,7 +1156,7 @@ Display_Or_Erase_Field(FIELD *field, bool bEraseFlag)
 
   if (!bEraseFlag)
     {
-      if ((unsigned)field->opts & O_PUBLIC)
+      if (Field_Has_Option(field, O_PUBLIC))
        {
          if (Justification_Allowed(field))
            Perform_Justification(field, win);
@@ -1170,7 +1202,7 @@ Synchronize_Field(FIELD *field)
          form->currow = form->curcol = form->toprow = form->begincol = 0;
          werase(form->w);
 
-         if (((unsigned)field->opts & O_PUBLIC) && Justification_Allowed(field))
+         if ((Field_Has_Option(field, O_PUBLIC)) && Justification_Allowed(field))
            Undo_Justification(field, form->w);
          else
            Buffer_To_Window(field, form->w);
@@ -1256,7 +1288,7 @@ _nc_Synchronize_Attributes(FIELD *field)
          werase(form->w);
          wmove(form->w, form->currow, form->curcol);
 
-         if ((unsigned)field->opts & O_PUBLIC)
+         if (Field_Has_Option(field, O_PUBLIC))
            {
              if (Justification_Allowed(field))
                Undo_Justification(field, form->w);
@@ -1269,7 +1301,8 @@ _nc_Synchronize_Attributes(FIELD *field)
              copywin(form->w, formwin,
                      0, 0,
                      field->frow, field->fcol,
-                     field->rows - 1, field->cols - 1, 0);
+                     field->frow + field->rows - 1,
+                     field->fcol + field->cols - 1, 0);
              wsyncup(formwin);
              Buffer_To_Window(field, form->w);
              SetStatus(field, _NEWTOP);        /* fake refresh to paint all */
@@ -1389,6 +1422,57 @@ _nc_Synchronize_Options(FIELD *field, Field_Options newopts)
   returnCode(res);
 }
 
+/*
+ * Removes the focus from the current field of the form.
+ */
+void
+_nc_Unset_Current_Field(FORM *form)
+{
+  FIELD *field = form->current;
+
+  _nc_Refresh_Current_Field(form);
+  if (Field_Has_Option(field, O_PUBLIC))
+    {
+      if (field->drows > field->rows)
+       {
+         if (form->toprow == 0)
+           ClrStatus(field, _NEWTOP);
+         else
+           SetStatus(field, _NEWTOP);
+       }
+      else
+       {
+         if (Justification_Allowed(field))
+           {
+             Window_To_Buffer(form, field);
+             werase(form->w);
+             Perform_Justification(field, form->w);
+             if (Field_Has_Option(field, O_DYNAMIC_JUSTIFY) &&
+                 (form->w->_parent == 0))
+               {
+                 copywin(form->w,
+                         Get_Form_Window(form),
+                         0,
+                         0,
+                         field->frow,
+                         field->fcol,
+                         field->frow,
+                         field->cols + field->fcol - 1,
+                         0);
+                 wsyncup(Get_Form_Window(form));
+               }
+             else
+               {
+                 wsyncup(form->w);
+               }
+           }
+       }
+    }
+  delwin(form->w);
+  form->w = (WINDOW *)0;
+  form->current = 0;
+}
+
 /*---------------------------------------------------------------------------
 |   Facility      :  libnform
 |   Function      :  int _nc_Set_Current_Field(FORM  * form,
@@ -1409,7 +1493,7 @@ _nc_Set_Current_Field(FORM *form, FIELD *newfield)
 
   T((T_CALLED("_nc_Set_Current_Field(%p,%p)"), (void *)form, (void *)newfield));
 
-  if (!form || !newfield || !form->current || (newfield->form != form))
+  if (!form || !newfield || (newfield->form != form))
     returnCode(E_BAD_ARGUMENT);
 
   if ((form->status & _IN_DRIVER))
@@ -1423,34 +1507,10 @@ _nc_Set_Current_Field(FORM *form, FIELD *newfield)
   if ((field != newfield) ||
       !(form->status & _POSTED))
     {
-      if ((form->w) &&
-         ((unsigned)field->opts & O_VISIBLE) &&
+      if (field && (form->w) &&
+         (Field_Has_Option(field, O_VISIBLE)) &&
          (field->form->curpage == field->page))
-       {
-         _nc_Refresh_Current_Field(form);
-         if ((unsigned)field->opts & O_PUBLIC)
-           {
-             if (field->drows > field->rows)
-               {
-                 if (form->toprow == 0)
-                   ClrStatus(field, _NEWTOP);
-                 else
-                   SetStatus(field, _NEWTOP);
-               }
-             else
-               {
-                 if (Justification_Allowed(field))
-                   {
-                     Window_To_Buffer(form, field);
-                     werase(form->w);
-                     Perform_Justification(field, form->w);
-                     wsyncup(form->w);
-                   }
-               }
-           }
-         delwin(form->w);
-         form->w = (WINDOW *)0;
-       }
+       _nc_Unset_Current_Field(form);
 
       field = newfield;
 
@@ -1998,7 +2058,7 @@ Vertical_Scrolling(int (*const fct) (FORM *), FORM *form)
     {
       res = fct(form);
       if (res == E_OK)
-       SetStatus(form, _NEWTOP);
+       SetStatus(form->current, _NEWTOP);
     }
   return (res);
 }
@@ -2430,7 +2490,7 @@ Wrapping_Not_Necessary_Or_Wrapping_Ok(FORM *form)
   int result = E_REQUEST_DENIED;
   bool Last_Row = ((field->drows - 1) == form->currow);
 
-  if (((unsigned)field->opts & O_WRAP) &&      /* wrapping wanted     */
+  if ((Field_Has_Option(field, O_WRAP)) &&     /* wrapping wanted     */
       (!Single_Line_Field(field)) &&   /* must be multi-line  */
       (There_Is_No_Room_For_A_Char_In_Line(form)) &&   /* line is full        */
       (!Last_Row || Growable(field)))  /* there are more lines */
@@ -3111,7 +3171,7 @@ Check_Field(FORM *form, FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
 {
   if (typ)
     {
-      if ((unsigned)field->opts & O_NULLOK)
+      if (Field_Has_Option(field, O_NULLOK))
        {
          FIELD_CELL *bp = field->buf;
 
@@ -3168,7 +3228,7 @@ _nc_Internal_Validation(FORM *form)
 
   Synchronize_Buffer(form);
   if ((form->status & _FCHECK_REQUIRED) ||
-      (!((unsigned)field->opts & O_PASSOK)))
+      (!(Field_Has_Option(field, O_PASSOK))))
     {
       if (!Check_Field(form, field->type, field, (TypeArgument *)(field->arg)))
        return FALSE;
@@ -3273,7 +3333,7 @@ _nc_First_Active_Field(FORM *form)
          do
            {
              field = (field == last_on_page) ? first : field + 1;
-             if (((unsigned)(*field)->opts & O_VISIBLE))
+             if (Field_Has_Option(*field, O_VISIBLE))
                break;
            }
          while (proposed != (*field));
@@ -4001,9 +4061,9 @@ Data_Entry_w(FORM *form, wchar_t c)
   int result = E_REQUEST_DENIED;
 
   T((T_CALLED("Data_Entry(%p,%s)"), (void *)form, _tracechtype((chtype)c)));
-  if (((unsigned)field->opts & O_EDIT)
+  if ((Field_Has_Option(field, O_EDIT))
 #if FIX_FORM_INACTIVE_BUG
-      && ((unsigned)field->opts & O_ACTIVE)
+      && (Field_Has_Option(field, O_ACTIVE))
 #endif
     )
     {
@@ -4011,9 +4071,9 @@ Data_Entry_w(FORM *form, wchar_t c)
       cchar_t temp_ch;
 
       given[0] = c;
-      given[1] = 1;
+      given[1] = 0;
       setcchar(&temp_ch, given, 0, 0, (void *)0);
-      if (((unsigned)field->opts & O_BLANK) &&
+      if ((Field_Has_Option(field, O_BLANK)) &&
          First_Position_In_Current_Field(form) &&
          !(form->status & _FCHECK_REQUIRED) &&
          !(form->status & _WINDOW_MODIFIED))
@@ -4044,7 +4104,7 @@ Data_Entry_w(FORM *form, wchar_t c)
                               ((field->dcols - 1) == form->curcol));
 
          form->status |= _WINDOW_MODIFIED;
-         if (End_Of_Field && !Growable(field) && ((unsigned)field->opts & O_AUTOSKIP))
+         if (End_Of_Field && !Growable(field) && (Field_Has_Option(field, O_AUTOSKIP)))
            result = Inter_Field_Navigation(FN_Next_Field, form);
          else
            {
@@ -4088,13 +4148,13 @@ Data_Entry(FORM *form, int c)
   int result = E_REQUEST_DENIED;
 
   T((T_CALLED("Data_Entry(%p,%s)"), (void *)form, _tracechtype((chtype)c)));
-  if (((unsigned)field->opts & O_EDIT)
+  if ((Field_Has_Option(field, O_EDIT))
 #if FIX_FORM_INACTIVE_BUG
-      && ((unsigned)field->opts & O_ACTIVE)
+      && (Field_Has_Option(field, O_ACTIVE))
 #endif
     )
     {
-      if (((unsigned)field->opts & O_BLANK) &&
+      if ((Field_Has_Option(field, O_BLANK)) &&
          First_Position_In_Current_Field(form) &&
          !(form->status & _FCHECK_REQUIRED) &&
          !(form->status & _WINDOW_MODIFIED))
@@ -4125,7 +4185,7 @@ Data_Entry(FORM *form, int c)
                               ((field->dcols - 1) == form->curcol));
 
          SetStatus(form, _WINDOW_MODIFIED);
-         if (End_Of_Field && !Growable(field) && ((unsigned)field->opts & O_AUTOSKIP))
+         if (End_Of_Field && !Growable(field) && (Field_Has_Option(field, O_AUTOSKIP)))
            result = Inter_Field_Navigation(FN_Next_Field, form);
          else
            {
@@ -4493,7 +4553,7 @@ form_driver_w(FORM *form, int type, wchar_t c)
   const Binding_Info *BI = (Binding_Info *) 0;
   int res = E_UNKNOWN_COMMAND;
 
-  T((T_CALLED("form_driver(%p,%d)"), (void *)form, (int) c));
+  T((T_CALLED("form_driver(%p,%d)"), (void *)form, (int)c));
 
   if (!form)
     RETURN(E_BAD_ARGUMENT);
@@ -4503,7 +4563,7 @@ form_driver_w(FORM *form, int type, wchar_t c)
 
   assert(form->page);
 
-  if (c == FIRST_ACTIVE_MAGIC)
+  if (c == (wchar_t)FIRST_ACTIVE_MAGIC)
     {
       form->current = _nc_First_Active_Field(form);
       RETURN(E_OK);
@@ -4905,7 +4965,7 @@ _nc_Widen_String(char *source, int *lengthp)
            {
              if (pass)
                {
-                 result[need] = source[passed];
+                 result[need] = (wchar_t)source[passed];
                }
              ++need;
              ++passed;