+#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;
co->left = left;
co->height = 1;
co->width = width;
- co->takesFocus = 1;
+ co->isMapped = 0;
+ co->callback = NULL;
+ co->destroyCallback = NULL;
co->ops = &entryOps;
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);
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);
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) {
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;
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;
+}