]> git.ipfire.org Git - thirdparty/newt.git/blobdiff - entry.c
install python modules to purelib and platlib
[thirdparty/newt.git] / entry.c
diff --git a/entry.c b/entry.c
index 9e9f9faf114f14708e032abb6ca8775010acf910..8dad8c8d5bf10c98582c9c0fc1a9c59d2cb4d29d 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -1,6 +1,14 @@
+#include "config.h"
+
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
 #include <ctype.h>
-#include <slang/slang.h>
+#include <slang.h>
 #include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
 
 #include "newt.h"
 #include "newt_pr.h"
 struct entry {
     int flags;
     char * buf;
-    char ** resultPtr;
+    const char ** resultPtr;
     int bufAlloced;
     int bufUsed;               /* amount of the buffer that's been used */
     int cursorPosition;        /* cursor *in the string* on on screen */
     int firstChar;             /* first character position being shown */
+    newtEntryFilter filter;
+    void * filterData;
+    int cs;
+    int csDisabled;
 };
 
+static int previous_char(const char *buf, int pos);
+static int next_char(const char *buf, int pos);
 static void entryDraw(newtComponent co);
 static void entryDestroy(newtComponent co);
-static struct eventResult entryEvent(struct newtComponent * co, 
+static struct eventResult entryEvent(newtComponent co,
                                     struct event ev);
 
-static struct eventResult entryHandleKey(struct newtComponent * co, int key);
+static struct eventResult entryHandleKey(newtComponent co, int key);
 
 static struct componentOps entryOps = {
     entryDraw,
     entryEvent,
     entryDestroy,
+    newtDefaultPlaceHandler,
+    newtDefaultMappedHandler,
 } ;
 
-newtComponent newtEntry(int left, int top, char * initialValue, int width,
-                       char ** resultPtr, int flags) {
+void newtEntrySet(newtComponent co, const char * value, int cursorAtEnd) {
+    struct entry * en = co->data;
+
+    if ((strlen(value) + 1) > (unsigned int)en->bufAlloced) {
+       free(en->buf);
+       en->bufAlloced = strlen(value) + 1;
+       en->buf = malloc(en->bufAlloced);
+       if (en->resultPtr) *en->resultPtr = en->buf;
+    }
+    memset(en->buf, 0, en->bufAlloced);                /* clear the buffer */
+    strcpy(en->buf, value);
+    en->bufUsed = strlen(value);
+    en->firstChar = 0;
+    if (cursorAtEnd)
+       en->cursorPosition = en->bufUsed;
+    else
+       en->cursorPosition = 0;
+
+    entryDraw(co);
+} ;
+
+newtComponent newtEntry(int left, int top, const char * initialValue, int width,
+                       const char ** resultPtr, int flags) {
     newtComponent co;
     struct entry * en;
 
@@ -41,7 +78,9 @@ newtComponent newtEntry(int left, int top, char * initialValue, int width,
     co->left = left;
     co->height = 1;
     co->width = width;
-    co->takesFocus = 1;
+    co->isMapped = 0;
+    co->callback = NULL;
+    co->destroyCallback = NULL;
 
     co->ops = &entryOps;
 
@@ -50,34 +89,112 @@ newtComponent newtEntry(int left, int top, char * initialValue, int width,
     en->firstChar = 0;
     en->bufUsed = 0;
     en->bufAlloced = width + 1;
+    en->filter = NULL;
 
-    if (initialValue && strlen(initialValue) > width) {
+    if (!(en->flags & NEWT_FLAG_DISABLED))
+       co->takesFocus = 1;
+    else
+       co->takesFocus = 0;
+
+    if (initialValue && strlen(initialValue) > (unsigned int)width) {
        en->bufAlloced = strlen(initialValue) + 1;
     }
     en->buf = malloc(en->bufAlloced);
-    *resultPtr = en->buf;
     en->resultPtr = resultPtr;
-  
+    if (en->resultPtr) *en->resultPtr = en->buf;
+
     memset(en->buf, 0, en->bufAlloced);
     if (initialValue) {
        strcpy(en->buf, initialValue);
        en->bufUsed = strlen(initialValue);
+       en->cursorPosition = en->bufUsed;
+
+       /* move cursor back if entry is full */
+       if (en->cursorPosition && !(en->flags & NEWT_FLAG_SCROLL ||
+                   wstrlen(en->buf, -1) < co->width))
+           en->cursorPosition = previous_char(en->buf, en->cursorPosition);
+    } else {
+       *en->buf = '\0';
+       en->bufUsed = 0;
+       en->cursorPosition = 0;
     }
 
+    en->cs = NEWT_COLORSET_ENTRY;
+    en->csDisabled = NEWT_COLORSET_DISENTRY;
+
     return co;
 }
 
+static void scroll(struct entry *en, int width)
+{
+    int r, lv, rv, cntx, cw, cn, nc, pc, ncw, pcw;
+
+    if (width <= 1) {
+       en->firstChar = en->cursorPosition;
+       return;
+    }
+
+    cntx = width / 4;
+    if (cntx > 5)
+       cntx = 5;
+
+    if (en->cursorPosition < en->firstChar)
+       en->firstChar = en->cursorPosition;
+
+    cn = next_char(en->buf, en->cursorPosition);
+    cw = en->cursorPosition >= en->bufUsed ? 1 :
+       wstrlen(en->buf + en->cursorPosition, cn - en->cursorPosition);
+
+    r = wstrlen(en->buf + cn, -1);
+
+    lv = wstrlen(en->buf + en->firstChar, en->cursorPosition - en->firstChar);
+    rv = width - lv - cw;
+
+#define RC (ncw > 0 && (r > rv && lv - ncw >= cntx && rv < cntx))
+#define LC (pcw > 0 && (r + pcw <= rv || (lv < cntx && rv - pcw >= cntx)))
+
+    nc = next_char(en->buf, en->firstChar);
+    ncw = wstrlen(en->buf + en->firstChar, nc - en->firstChar);
+    if (RC) {
+       do {
+           lv -= ncw;
+           rv += ncw;
+           en->firstChar = nc;
+           nc = next_char(en->buf, en->firstChar);
+           ncw = wstrlen(en->buf + en->firstChar, nc - en->firstChar);
+       } while (RC);
+       return;
+    }
+
+    pc = previous_char(en->buf, en->firstChar);
+    pcw = wstrlen(en->buf + pc, en->firstChar - pc);
+    if (LC) {
+       do {
+           lv += pcw;
+           rv -= pcw;
+           en->firstChar = pc;
+           pc = previous_char(en->buf, en->firstChar);
+           pcw = wstrlen(en->buf + pc, en->firstChar - pc);
+       } while (LC);
+    }
+}
+
 static void entryDraw(newtComponent co) {
     struct entry * en = co->data;
     int i;
     char * chptr;
     int len;
+    char *tmpptr = NULL;
+
+    if (!co->isMapped) return;
 
-    if (co->top == -1) return;
-    if (en->flags & NEWT_ENTRY_HIDDEN) {
+    if (en->flags & NEWT_FLAG_DISABLED)
+       SLsmg_set_color(en->csDisabled);
+    else
+       SLsmg_set_color(en->cs);
+
+    if (en->flags & NEWT_FLAG_HIDDEN) {
        newtGotorc(co->top, co->left);
-       SLsmg_set_color(COLORSET_ENTRY);
        for (i = 0; i < co->width; i++)
            SLsmg_write_char('_');
        newtGotorc(co->top, co->left);
@@ -85,20 +202,35 @@ static void entryDraw(newtComponent co) {
        return;
     }
 
-    newtGotorc(co->top, co->left);
-    SLsmg_set_color(COLORSET_ENTRY);
+    newtTrashScreen();
 
-    if (en->cursorPosition < en->firstChar) {
-       /* scroll to the left */
-       en->firstChar = en->cursorPosition;
-    } else if ((en->firstChar + co->width) <= en->cursorPosition) {
-       /* scroll to the right */
-       en->firstChar = en->cursorPosition - co->width + 1;
-    }
+    /* scroll if necessary */
+    scroll(en, co->width);
 
     chptr = en->buf + en->firstChar;
-    len = strlen(chptr);
+
+    if (en->flags & NEWT_FLAG_PASSWORD) {
+       len = wstrlen(chptr, -1);
+       tmpptr = alloca(len + 1);
+       for (i = 0; i < len; i++)
+           memset(tmpptr, '*', len);
+       tmpptr[len] = '\0';
+       chptr = tmpptr;
+    }                  
+
+    len = wstrlen(chptr, -1);
+
+    /* workaround for double width characters */
+    if (co->width > 1) {
+       i = len < co->width ? len : co->width;
+       i = i > 2 ? i - 2 : 0;
+       newtGotorc(co->top, co->left + i);
+       SLsmg_write_char('_');
+       SLsmg_write_char('_');
+    }
+
+    newtGotorc(co->top, co->left);
+
     if (len <= co->width) {
        i = len;
        SLsmg_write_string(chptr);
@@ -106,11 +238,34 @@ static void entryDraw(newtComponent co) {
            SLsmg_write_char('_');
            i++;
        }
-    } else {
+    } else
        SLsmg_write_nstring(chptr, co->width);
-    }
 
-    newtGotorc(co->top, co->left + (en->cursorPosition - en->firstChar));
+    newtGotorc(co->top, co->left + wstrlen(en->buf+en->firstChar, en->cursorPosition - en->firstChar));
+}
+
+void newtEntrySetFlags(newtComponent co, int flags, enum newtFlagsSense sense) {
+    struct entry * en = co->data;
+    int row, col;
+
+    en->flags = newtSetFlags(en->flags, flags, sense);
+
+    if (!(en->flags & NEWT_FLAG_DISABLED))
+       co->takesFocus = 1;
+    else
+       co->takesFocus = 0;
+
+    newtGetrc(&row, &col);
+    entryDraw(co);
+    newtGotorc(row, col);
+}
+
+void newtEntrySetColors(newtComponent co, int normal, int disabled) {
+    struct entry * en = co->data;
+
+    en->cs = normal;
+    en->csDisabled = disabled;
+    entryDraw(co);
 }
 
 static void entryDestroy(newtComponent co) {
@@ -121,43 +276,99 @@ static void entryDestroy(newtComponent co) {
     free(co);
 }
 
-static struct eventResult entryEvent(struct newtComponent * co, 
+static struct eventResult entryEvent(newtComponent co,
                                     struct event ev) {
     struct entry * en = co->data;
     struct eventResult er;
+    int ch;
+
+    er.result = ER_IGNORED;
 
     if (ev.when == EV_NORMAL) {
        switch (ev.event) {
-         case EV_FOCUS:
-           /*SLtt_set_cursor_visibility(0);*/
-           newtGotorc(co->top, co->left + 
-                               (en->cursorPosition - en->firstChar));
+       case EV_FOCUS:
+           newtCursorOn();
+           if (en->flags & NEWT_FLAG_HIDDEN)
+               newtGotorc(co->top, co->left);
+           else
+               newtGotorc(co->top, co->left +
+                          wstrlen(en->buf + en->firstChar, en->cursorPosition - en->firstChar));
            er.result = ER_SWALLOWED;
            break;
 
-         case EV_UNFOCUS:
-           /*SLtt_set_cursor_visibility(1);*/
+       case EV_UNFOCUS:
+           newtCursorOff();
            newtGotorc(0, 0);
            er.result = ER_SWALLOWED;
+           if (co->callback)
+               co->callback(co, co->callbackData);
+           break;
+
+       case EV_KEYPRESS:
+           ch = ev.u.key;
+           if (en->filter)
+               ch = en->filter(co, en->filterData, ch, en->cursorPosition);
+           if (ch) er = entryHandleKey(co, ch);
            break;
 
-         case EV_KEYPRESS:
-           er = entryHandleKey(co, ev.u.key);
+       case EV_MOUSE:
+           if ((ev.u.mouse.type == MOUSE_BUTTON_DOWN) &&
+               (en->flags ^ NEWT_FLAG_HIDDEN)) {
+               if (strlen(en->buf) >= ev.u.mouse.x - co->left) {
+                   en->cursorPosition = ev.u.mouse.x - co->left;
+                   newtGotorc(co->top,
+                              co->left +(en->cursorPosition - en->firstChar));
+               } else {
+                   en->cursorPosition = strlen(en->buf);
+                   newtGotorc(co->top,
+                              co->left +(en->cursorPosition - en->firstChar));
+               }
+           }
            break;
        }
-    } else
-       er.result = ER_IGNORED;
+    }
 
     return er;
 }
 
-static struct eventResult entryHandleKey(struct newtComponent * co, int key) {
+static int previous_char(const char *buf, int pos)
+{
+    int len = 0;
+    int off = 0;
+    
+    while (off < pos) {
+       len = mblen(buf+off, MB_CUR_MAX);
+       if (len <= 0)
+         return pos;
+       off+=len;
+    }
+    return off-len;
+}
+
+static int next_char(const char *buf, int pos)
+{
+    int len = mblen(buf + pos, MB_CUR_MAX);
+    if (len <= 0)
+       return pos;
+    return pos+len;
+}
+
+static struct eventResult entryHandleKey(newtComponent co, int key) {
     struct entry * en = co->data;
     struct eventResult er;
-    char * chptr, * insPoint;
+    char * chptr;
 
     er.result = ER_SWALLOWED;
     switch (key) {
+      case '\r':                               /* Return */
+       if (en->flags & NEWT_FLAG_RETURNEXIT) {
+           newtCursorOff();
+           er.result = ER_EXITFORM;
+       } else {
+           er.result = ER_NEXTCOMP;
+       }
+       break;
+
       case '\001':                             /* ^A */
       case NEWT_KEY_HOME:
        en->cursorPosition = 0;
@@ -173,89 +384,135 @@ static struct eventResult entryHandleKey(struct newtComponent * co, int key) {
        memset(en->buf + en->bufUsed, 0, en->bufAlloced - en->bufUsed);
        break;
 
+      case '\025':                             /* ^U */
+       en->bufUsed -= en->cursorPosition;
+       memmove(en->buf, en->buf + en->cursorPosition, en->bufUsed);
+       en->cursorPosition = 0;
+       memset(en->buf + en->bufUsed, 0, en->bufAlloced - en->bufUsed);
+       break;
+
       case '\002':                             /* ^B */
       case NEWT_KEY_LEFT:
        if (en->cursorPosition)
-           en->cursorPosition--;
+           en->cursorPosition = previous_char(en->buf, en->cursorPosition);
        break;
 
       case '\004':
       case NEWT_KEY_DELETE:
        chptr = en->buf + en->cursorPosition;
        if (*chptr) {
-           chptr++;
-           while (*chptr) {
-               *(chptr - 1) = *chptr;
-               chptr++;
+           int delta = next_char(en->buf, en->cursorPosition)-en->cursorPosition;
+           if (delta) {
+              chptr+=delta;
+              while (*chptr) {
+                 *(chptr - delta) = *chptr;
+                 chptr++;
+              }
+              memset(chptr - delta, 0, delta);
+              en->bufUsed-=delta;
            }
-           *(chptr - 1) = '\0';
-           en->bufUsed--;
        }
        break;
 
-      case NEWT_KEY_BKSPC:
-       if (en->cursorPosition) {
+      case NEWT_KEY_BKSPC: {
+       int prev = previous_char(en->buf, en->cursorPosition);
+       if (en->cursorPosition != prev) {
            /* if this isn't true, there's nothing to erase */
+           int delta = en->cursorPosition - prev;
            chptr = en->buf + en->cursorPosition;
-           en->bufUsed--;
-           en->cursorPosition--;
+           en->bufUsed-=delta;
+           en->cursorPosition-=delta;
            while (*chptr) {
-               *(chptr - 1) = *chptr;
+               *(chptr - delta) = *chptr;
                chptr++;
            }
-           *(chptr - 1) = '\0';
+           memset(chptr - delta, 0, delta);
+       }
        }
        break;
 
       case '\006':                             /* ^B */
       case NEWT_KEY_RIGHT:
        if (en->cursorPosition < en->bufUsed)
-           en->cursorPosition++;
+           en->cursorPosition = next_char(en->buf, en->cursorPosition);
        break;
 
       default:
-       if ((key >= 0x20 && key <= 0x7e) || (key >= 0xa0 && key <= 0xff)) {
-           if (!(en->flags & NEWT_ENTRY_SCROLL) && en->bufUsed == co->width) {
+       if ((key >= 0x20 && key <= 0x7e) || (key >= 0x80 && key <= 0xff)) {
+           char s[MB_CUR_MAX];
+           mbstate_t ps;
+           int i, l;
+
+           for (i = 1, s[0] = key; ; i++) {
+               memset(&ps, 0, sizeof (ps));
+               l = mbrtowc(NULL, s, i, &ps);
+               if (l == -1)    /* invalid sequence */
+                   i = 0;
+               if (l != -2)    /* not incomplete sequence */
+                   break;
+
+               /* read next byte */
+               if (i == MB_CUR_MAX || !SLang_input_pending(1)) {
+                   i = 0;
+                   break;
+               }
+               s[i] = SLang_getkey();
+           }
+
+           if (!i || (!(en->flags & NEWT_FLAG_SCROLL) && wstrlen(en->buf, -1) + wstrlen(s, i) > co->width)) {
+               /* FIXME this is broken */
                SLtt_beep();
                break;
-           } 
-       
-           if ((en->bufUsed + 1) == en->bufAlloced) {
+           }
+
+           if ((en->bufUsed + i) >= en->bufAlloced) {
                en->bufAlloced += 20;
                en->buf = realloc(en->buf, en->bufAlloced);
-               *en->resultPtr = en->buf;
-               memset(en->buf + en->bufUsed + 1, 0, 20);
+               if (en->resultPtr) *en->resultPtr = en->buf;
+               memset(en->buf + en->bufAlloced - 20, 0, 20);
            }
 
-           if (en->cursorPosition == en->bufUsed) {
-               en->bufUsed++;
-           } else {
+           if (en->cursorPosition != en->bufUsed) {
                /* insert the new character */
-
-               /* chptr is the last character in the string */
-               chptr = (en->buf + en->bufUsed) - 1;
-               if ((en->bufUsed + 1) == en->bufAlloced) {
-                   /* this string fills the buffer, so clip it */
-                   chptr--;
-               } else 
-                   en->bufUsed++;
-
-               insPoint = en->buf + en->cursorPosition;
-
-               while (chptr >= insPoint) {
-                   *(chptr + 1) = *chptr;
-                   chptr--;
-               }
-
+               memmove(en->buf + en->cursorPosition + i, en->buf + en->cursorPosition, en->bufUsed - en->cursorPosition);
            }
-               
-           en->buf[en->cursorPosition++] = key;
+           en->bufUsed += i;
+           for (l = 0; l < i; l++)
+               en->buf[en->cursorPosition++] = s[l];
        } else {
            er.result = ER_IGNORED;
        }
-    } 
+    }
+
+    if (en->cursorPosition == en->bufUsed && en->cursorPosition &&
+           !(en->flags & NEWT_FLAG_SCROLL || wstrlen(en->buf, -1) < co->width))
+       en->cursorPosition = previous_char(en->buf, en->cursorPosition);
 
     entryDraw(co);
 
     return er;
 }
+
+char * newtEntryGetValue(newtComponent co) {
+    struct entry * en = co->data;
+
+    return en->buf;
+}
+
+void newtEntrySetFilter(newtComponent co, newtEntryFilter filter, void * data) {
+    struct entry * en = co->data;
+    en->filter = filter;
+    en->filterData = data;
+}
+
+int newtEntryGetCursorPosition (newtComponent co) {
+    struct entry * en = co->data;
+
+    return en->cursorPosition;
+}
+
+void newtEntrySetCursorPosition (newtComponent co, int position) {
+    struct entry * en = co->data;
+
+    en->cursorPosition = position;
+}