]>
Commit | Line | Data |
---|---|---|
d638bf45 | 1 | #include "config.h" |
2 | ||
3 | #ifdef HAVE_ALLOCA_H | |
4 | #include <alloca.h> | |
5 | #endif | |
6 | ||
6fb96a3f | 7 | #include <ctype.h> |
139f06bc | 8 | #include <slang.h> |
6fb96a3f | 9 | #include <stdlib.h> |
fec0af06 | 10 | #include <string.h> |
feef2cb5 | 11 | #include <wchar.h> |
6fb96a3f | 12 | |
13 | #include "newt.h" | |
14 | #include "newt_pr.h" | |
15 | ||
16 | struct entry { | |
17 | int flags; | |
18 | char * buf; | |
d78245ab | 19 | const char ** resultPtr; |
6fb96a3f | 20 | int bufAlloced; |
6f481af2 | 21 | int bufUsed; /* amount of the buffer that's been used */ |
22 | int cursorPosition; /* cursor *in the string* on on screen */ | |
23 | int firstChar; /* first character position being shown */ | |
fad2cd5f | 24 | newtEntryFilter filter; |
25 | void * filterData; | |
099b22e5 ML |
26 | int cs; |
27 | int csDisabled; | |
6fb96a3f | 28 | }; |
29 | ||
4d4a4e20 | 30 | static int previous_char(const char *buf, int pos); |
31 | static int next_char(const char *buf, int pos); | |
6fb96a3f | 32 | static void entryDraw(newtComponent co); |
33 | static void entryDestroy(newtComponent co); | |
45f6c4fd | 34 | static struct eventResult entryEvent(newtComponent co, |
6f481af2 | 35 | struct event ev); |
6fb96a3f | 36 | |
45c366b1 | 37 | static struct eventResult entryHandleKey(newtComponent co, int key); |
6fb96a3f | 38 | |
39 | static struct componentOps entryOps = { | |
40 | entryDraw, | |
41 | entryEvent, | |
42 | entryDestroy, | |
8f52cd47 | 43 | newtDefaultPlaceHandler, |
44 | newtDefaultMappedHandler, | |
6fb96a3f | 45 | } ; |
46 | ||
d4109c37 | 47 | void newtEntrySet(newtComponent co, const char * value, int cursorAtEnd) { |
8121f050 | 48 | struct entry * en = co->data; |
49 | ||
a880525e | 50 | if ((strlen(value) + 1) > (unsigned int)en->bufAlloced) { |
6f481af2 | 51 | free(en->buf); |
52 | en->bufAlloced = strlen(value) + 1; | |
53 | en->buf = malloc(en->bufAlloced); | |
54 | if (en->resultPtr) *en->resultPtr = en->buf; | |
8121f050 | 55 | } |
6f481af2 | 56 | memset(en->buf, 0, en->bufAlloced); /* clear the buffer */ |
8121f050 | 57 | strcpy(en->buf, value); |
58 | en->bufUsed = strlen(value); | |
59 | en->firstChar = 0; | |
60 | if (cursorAtEnd) | |
6f481af2 | 61 | en->cursorPosition = en->bufUsed; |
8121f050 | 62 | else |
6f481af2 | 63 | en->cursorPosition = 0; |
8121f050 | 64 | |
65 | entryDraw(co); | |
66 | } ; | |
67 | ||
d4109c37 | 68 | newtComponent newtEntry(int left, int top, const char * initialValue, int width, |
6f481af2 | 69 | const char ** resultPtr, int flags) { |
6fb96a3f | 70 | newtComponent co; |
71 | struct entry * en; | |
72 | ||
73 | co = malloc(sizeof(*co)); | |
74 | en = malloc(sizeof(struct entry)); | |
75 | co->data = en; | |
76 | ||
77 | co->top = top; | |
78 | co->left = left; | |
79 | co->height = 1; | |
80 | co->width = width; | |
8f52cd47 | 81 | co->isMapped = 0; |
f4eeb9ee | 82 | co->callback = NULL; |
c101e99e | 83 | co->destroyCallback = NULL; |
6fb96a3f | 84 | |
85 | co->ops = &entryOps; | |
86 | ||
87 | en->flags = flags; | |
88 | en->cursorPosition = 0; | |
89 | en->firstChar = 0; | |
90 | en->bufUsed = 0; | |
91 | en->bufAlloced = width + 1; | |
fad2cd5f | 92 | en->filter = NULL; |
6fb96a3f | 93 | |
4a93351d | 94 | if (!(en->flags & NEWT_FLAG_DISABLED)) |
6f481af2 | 95 | co->takesFocus = 1; |
38f35ccd | 96 | else |
6f481af2 | 97 | co->takesFocus = 0; |
38f35ccd | 98 | |
feef2cb5 | 99 | if (initialValue && strlen(initialValue) > (unsigned int)width) { |
100 | en->bufAlloced = strlen(initialValue) + 1; | |
6fb96a3f | 101 | } |
102 | en->buf = malloc(en->bufAlloced); | |
6fb96a3f | 103 | en->resultPtr = resultPtr; |
fad2cd5f | 104 | if (en->resultPtr) *en->resultPtr = en->buf; |
45f6c4fd | 105 | |
6fb96a3f | 106 | memset(en->buf, 0, en->bufAlloced); |
107 | if (initialValue) { | |
6f481af2 | 108 | strcpy(en->buf, initialValue); |
109 | en->bufUsed = strlen(initialValue); | |
110 | en->cursorPosition = en->bufUsed; | |
4d4a4e20 | 111 | |
112 | /* move cursor back if entry is full */ | |
113 | if (en->cursorPosition && !(en->flags & NEWT_FLAG_SCROLL || | |
114 | wstrlen(en->buf, -1) < co->width)) | |
115 | en->cursorPosition = previous_char(en->buf, en->cursorPosition); | |
78d39fcf | 116 | } else { |
6f481af2 | 117 | *en->buf = '\0'; |
118 | en->bufUsed = 0; | |
119 | en->cursorPosition = 0; | |
6fb96a3f | 120 | } |
121 | ||
099b22e5 ML |
122 | en->cs = NEWT_COLORSET_ENTRY; |
123 | en->csDisabled = NEWT_COLORSET_DISENTRY; | |
124 | ||
6fb96a3f | 125 | return co; |
126 | } | |
127 | ||
feef2cb5 | 128 | static void scroll(struct entry *en, int width) |
129 | { | |
4d4a4e20 | 130 | int r, lv, rv, cntx, cw, cn, nc, pc, ncw, pcw; |
131 | ||
132 | if (width <= 1) { | |
133 | en->firstChar = en->cursorPosition; | |
134 | return; | |
135 | } | |
136 | ||
137 | cntx = width / 4; | |
138 | if (cntx > 5) | |
139 | cntx = 5; | |
140 | ||
141 | if (en->cursorPosition < en->firstChar) | |
142 | en->firstChar = en->cursorPosition; | |
143 | ||
144 | cn = next_char(en->buf, en->cursorPosition); | |
145 | cw = en->cursorPosition >= en->bufUsed ? 1 : | |
146 | wstrlen(en->buf + en->cursorPosition, cn - en->cursorPosition); | |
147 | ||
148 | r = wstrlen(en->buf + cn, -1); | |
149 | ||
150 | lv = wstrlen(en->buf + en->firstChar, en->cursorPosition - en->firstChar); | |
151 | rv = width - lv - cw; | |
152 | ||
153 | #define RC (ncw > 0 && (r > rv && lv - ncw >= cntx && rv < cntx)) | |
154 | #define LC (pcw > 0 && (r + pcw <= rv || (lv < cntx && rv - pcw >= cntx))) | |
155 | ||
156 | nc = next_char(en->buf, en->firstChar); | |
157 | ncw = wstrlen(en->buf + en->firstChar, nc - en->firstChar); | |
158 | if (RC) { | |
159 | do { | |
160 | lv -= ncw; | |
161 | rv += ncw; | |
162 | en->firstChar = nc; | |
163 | nc = next_char(en->buf, en->firstChar); | |
164 | ncw = wstrlen(en->buf + en->firstChar, nc - en->firstChar); | |
165 | } while (RC); | |
166 | return; | |
167 | } | |
168 | ||
169 | pc = previous_char(en->buf, en->firstChar); | |
170 | pcw = wstrlen(en->buf + pc, en->firstChar - pc); | |
171 | if (LC) { | |
172 | do { | |
173 | lv += pcw; | |
174 | rv -= pcw; | |
175 | en->firstChar = pc; | |
176 | pc = previous_char(en->buf, en->firstChar); | |
177 | pcw = wstrlen(en->buf + pc, en->firstChar - pc); | |
178 | } while (LC); | |
feef2cb5 | 179 | } |
180 | } | |
181 | ||
6fb96a3f | 182 | static void entryDraw(newtComponent co) { |
183 | struct entry * en = co->data; | |
184 | int i; | |
185 | char * chptr; | |
186 | int len; | |
feef2cb5 | 187 | char *tmpptr = NULL; |
94396885 | 188 | |
8f52cd47 | 189 | if (!co->isMapped) return; |
38f35ccd | 190 | |
45f6c4fd | 191 | if (en->flags & NEWT_FLAG_DISABLED) |
099b22e5 | 192 | SLsmg_set_color(en->csDisabled); |
38f35ccd | 193 | else |
099b22e5 | 194 | SLsmg_set_color(en->cs); |
45f6c4fd | 195 | |
4a93351d | 196 | if (en->flags & NEWT_FLAG_HIDDEN) { |
6f481af2 | 197 | newtGotorc(co->top, co->left); |
198 | for (i = 0; i < co->width; i++) | |
199 | SLsmg_write_char('_'); | |
200 | newtGotorc(co->top, co->left); | |
6fb96a3f | 201 | |
6f481af2 | 202 | return; |
6fb96a3f | 203 | } |
204 | ||
3aab8830 | 205 | newtTrashScreen(); |
206 | ||
4d4a4e20 | 207 | /* scroll if necessary */ |
208 | scroll(en, co->width); | |
6fb96a3f | 209 | |
210 | chptr = en->buf + en->firstChar; | |
20fb366a | 211 | |
212 | if (en->flags & NEWT_FLAG_PASSWORD) { | |
2a157d55 | 213 | len = wstrlen(chptr, -1); |
214 | tmpptr = alloca(len + 1); | |
215 | for (i = 0; i < len; i++) | |
216 | memset(tmpptr, '*', len); | |
217 | tmpptr[len] = '\0'; | |
6f481af2 | 218 | chptr = tmpptr; |
219 | } | |
20fb366a | 220 | |
ce11acc8 | 221 | len = wstrlen(chptr, -1); |
45f6c4fd | 222 | |
f423597b | 223 | /* workaround for double width characters */ |
224 | if (co->width > 1) { | |
225 | i = len < co->width ? len : co->width; | |
226 | i = i > 2 ? i - 2 : 0; | |
227 | newtGotorc(co->top, co->left + i); | |
228 | SLsmg_write_char('_'); | |
229 | SLsmg_write_char('_'); | |
230 | } | |
231 | ||
232 | newtGotorc(co->top, co->left); | |
233 | ||
6fb96a3f | 234 | if (len <= co->width) { |
6f481af2 | 235 | i = len; |
236 | SLsmg_write_string(chptr); | |
237 | while (i < co->width) { | |
238 | SLsmg_write_char('_'); | |
239 | i++; | |
240 | } | |
8e0e899c ML |
241 | } else |
242 | SLsmg_write_nstring(chptr, co->width); | |
6fb96a3f | 243 | |
f423597b | 244 | newtGotorc(co->top, co->left + wstrlen(en->buf+en->firstChar, en->cursorPosition - en->firstChar)); |
6fb96a3f | 245 | } |
246 | ||
38f35ccd | 247 | void newtEntrySetFlags(newtComponent co, int flags, enum newtFlagsSense sense) { |
248 | struct entry * en = co->data; | |
249 | int row, col; | |
250 | ||
251 | en->flags = newtSetFlags(en->flags, flags, sense); | |
252 | ||
4a93351d | 253 | if (!(en->flags & NEWT_FLAG_DISABLED)) |
6f481af2 | 254 | co->takesFocus = 1; |
38f35ccd | 255 | else |
6f481af2 | 256 | co->takesFocus = 0; |
38f35ccd | 257 | |
258 | newtGetrc(&row, &col); | |
259 | entryDraw(co); | |
260 | newtGotorc(row, col); | |
261 | } | |
262 | ||
099b22e5 ML |
263 | void newtEntrySetColors(newtComponent co, int normal, int disabled) { |
264 | struct entry * en = co->data; | |
265 | ||
266 | en->cs = normal; | |
267 | en->csDisabled = disabled; | |
268 | entryDraw(co); | |
269 | } | |
270 | ||
6fb96a3f | 271 | static void entryDestroy(newtComponent co) { |
272 | struct entry * en = co->data; | |
273 | ||
274 | free(en->buf); | |
275 | free(en); | |
276 | free(co); | |
277 | } | |
278 | ||
45f6c4fd | 279 | static struct eventResult entryEvent(newtComponent co, |
6f481af2 | 280 | struct event ev) { |
6fb96a3f | 281 | struct entry * en = co->data; |
282 | struct eventResult er; | |
fad2cd5f | 283 | int ch; |
6fb96a3f | 284 | |
c00a8d1b | 285 | er.result = ER_IGNORED; |
286 | ||
c1a075d9 | 287 | if (ev.when == EV_NORMAL) { |
6f481af2 | 288 | switch (ev.event) { |
289 | case EV_FOCUS: | |
290 | newtCursorOn(); | |
291 | if (en->flags & NEWT_FLAG_HIDDEN) | |
292 | newtGotorc(co->top, co->left); | |
293 | else | |
294 | newtGotorc(co->top, co->left + | |
feef2cb5 | 295 | wstrlen(en->buf + en->firstChar, en->cursorPosition - en->firstChar)); |
6f481af2 | 296 | er.result = ER_SWALLOWED; |
297 | break; | |
298 | ||
299 | case EV_UNFOCUS: | |
300 | newtCursorOff(); | |
301 | newtGotorc(0, 0); | |
302 | er.result = ER_SWALLOWED; | |
303 | if (co->callback) | |
304 | co->callback(co, co->callbackData); | |
305 | break; | |
306 | ||
307 | case EV_KEYPRESS: | |
308 | ch = ev.u.key; | |
309 | if (en->filter) | |
310 | ch = en->filter(co, en->filterData, ch, en->cursorPosition); | |
311 | if (ch) er = entryHandleKey(co, ch); | |
312 | break; | |
313 | ||
314 | case EV_MOUSE: | |
315 | if ((ev.u.mouse.type == MOUSE_BUTTON_DOWN) && | |
316 | (en->flags ^ NEWT_FLAG_HIDDEN)) { | |
317 | if (strlen(en->buf) >= ev.u.mouse.x - co->left) { | |
318 | en->cursorPosition = ev.u.mouse.x - co->left; | |
319 | newtGotorc(co->top, | |
320 | co->left +(en->cursorPosition - en->firstChar)); | |
321 | } else { | |
322 | en->cursorPosition = strlen(en->buf); | |
323 | newtGotorc(co->top, | |
324 | co->left +(en->cursorPosition - en->firstChar)); | |
325 | } | |
326 | } | |
327 | break; | |
328 | } | |
c00a8d1b | 329 | } |
6fb96a3f | 330 | |
331 | return er; | |
332 | } | |
333 | ||
feef2cb5 | 334 | static int previous_char(const char *buf, int pos) |
335 | { | |
336 | int len = 0; | |
337 | int off = 0; | |
338 | ||
339 | while (off < pos) { | |
340 | len = mblen(buf+off, MB_CUR_MAX); | |
341 | if (len <= 0) | |
342 | return pos; | |
343 | off+=len; | |
344 | } | |
345 | return off-len; | |
346 | } | |
347 | ||
348 | static int next_char(const char *buf, int pos) | |
349 | { | |
350 | int len = mblen(buf + pos, MB_CUR_MAX); | |
4d4a4e20 | 351 | if (len <= 0) |
feef2cb5 | 352 | return pos; |
feef2cb5 | 353 | return pos+len; |
354 | } | |
355 | ||
45c366b1 | 356 | static struct eventResult entryHandleKey(newtComponent co, int key) { |
6fb96a3f | 357 | struct entry * en = co->data; |
358 | struct eventResult er; | |
4d4a4e20 | 359 | char * chptr; |
6fb96a3f | 360 | |
361 | er.result = ER_SWALLOWED; | |
362 | switch (key) { | |
6f481af2 | 363 | case '\r': /* Return */ |
364 | if (en->flags & NEWT_FLAG_RETURNEXIT) { | |
e5437c85 | 365 | newtCursorOff(); |
6f481af2 | 366 | er.result = ER_EXITFORM; |
367 | } else { | |
368 | er.result = ER_NEXTCOMP; | |
369 | } | |
370 | break; | |
371 | ||
372 | case '\001': /* ^A */ | |
6fb96a3f | 373 | case NEWT_KEY_HOME: |
6f481af2 | 374 | en->cursorPosition = 0; |
375 | break; | |
6fb96a3f | 376 | |
6f481af2 | 377 | case '\005': /* ^E */ |
6fb96a3f | 378 | case NEWT_KEY_END: |
6f481af2 | 379 | en->cursorPosition = en->bufUsed; |
380 | break; | |
6fb96a3f | 381 | |
6f481af2 | 382 | case '\013': /* ^K */ |
383 | en->bufUsed = en->cursorPosition; | |
384 | memset(en->buf + en->bufUsed, 0, en->bufAlloced - en->bufUsed); | |
385 | break; | |
6fb96a3f | 386 | |
feef2cb5 | 387 | case '\025': /* ^U */ |
388 | en->bufUsed -= en->cursorPosition; | |
389 | memmove(en->buf, en->buf + en->cursorPosition, en->bufUsed); | |
390 | en->cursorPosition = 0; | |
391 | memset(en->buf + en->bufUsed, 0, en->bufAlloced - en->bufUsed); | |
392 | break; | |
393 | ||
6f481af2 | 394 | case '\002': /* ^B */ |
6fb96a3f | 395 | case NEWT_KEY_LEFT: |
6f481af2 | 396 | if (en->cursorPosition) |
feef2cb5 | 397 | en->cursorPosition = previous_char(en->buf, en->cursorPosition); |
6f481af2 | 398 | break; |
6fb96a3f | 399 | |
400 | case '\004': | |
401 | case NEWT_KEY_DELETE: | |
6f481af2 | 402 | chptr = en->buf + en->cursorPosition; |
403 | if (*chptr) { | |
feef2cb5 | 404 | int delta = next_char(en->buf, en->cursorPosition)-en->cursorPosition; |
405 | if (delta) { | |
406 | chptr+=delta; | |
407 | while (*chptr) { | |
408 | *(chptr - delta) = *chptr; | |
409 | chptr++; | |
410 | } | |
411 | memset(chptr - delta, 0, delta); | |
412 | en->bufUsed-=delta; | |
6f481af2 | 413 | } |
6f481af2 | 414 | } |
415 | break; | |
6fb96a3f | 416 | |
feef2cb5 | 417 | case NEWT_KEY_BKSPC: { |
418 | int prev = previous_char(en->buf, en->cursorPosition); | |
419 | if (en->cursorPosition != prev) { | |
6f481af2 | 420 | /* if this isn't true, there's nothing to erase */ |
feef2cb5 | 421 | int delta = en->cursorPosition - prev; |
6f481af2 | 422 | chptr = en->buf + en->cursorPosition; |
feef2cb5 | 423 | en->bufUsed-=delta; |
424 | en->cursorPosition-=delta; | |
6f481af2 | 425 | while (*chptr) { |
feef2cb5 | 426 | *(chptr - delta) = *chptr; |
6f481af2 | 427 | chptr++; |
428 | } | |
feef2cb5 | 429 | memset(chptr - delta, 0, delta); |
430 | } | |
6f481af2 | 431 | } |
432 | break; | |
433 | ||
434 | case '\006': /* ^B */ | |
6fb96a3f | 435 | case NEWT_KEY_RIGHT: |
6f481af2 | 436 | if (en->cursorPosition < en->bufUsed) |
feef2cb5 | 437 | en->cursorPosition = next_char(en->buf, en->cursorPosition); |
6f481af2 | 438 | break; |
6fb96a3f | 439 | |
440 | default: | |
feef2cb5 | 441 | if ((key >= 0x20 && key <= 0x7e) || (key >= 0x80 && key <= 0xff)) { |
4062a29f | 442 | char s[MB_CUR_MAX]; |
443 | mbstate_t ps; | |
444 | int i, l; | |
445 | ||
446 | for (i = 1, s[0] = key; ; i++) { | |
447 | memset(&ps, 0, sizeof (ps)); | |
448 | l = mbrtowc(NULL, s, i, &ps); | |
449 | if (l == -1) /* invalid sequence */ | |
450 | i = 0; | |
451 | if (l != -2) /* not incomplete sequence */ | |
452 | break; | |
453 | ||
454 | /* read next byte */ | |
455 | if (i == MB_CUR_MAX || !SLang_input_pending(1)) { | |
456 | i = 0; | |
457 | break; | |
458 | } | |
459 | s[i] = SLang_getkey(); | |
460 | } | |
461 | ||
4d4a4e20 | 462 | if (!i || (!(en->flags & NEWT_FLAG_SCROLL) && wstrlen(en->buf, -1) + wstrlen(s, i) > co->width)) { |
feef2cb5 | 463 | /* FIXME this is broken */ |
6f481af2 | 464 | SLtt_beep(); |
465 | break; | |
466 | } | |
467 | ||
4062a29f | 468 | if ((en->bufUsed + i) >= en->bufAlloced) { |
6f481af2 | 469 | en->bufAlloced += 20; |
470 | en->buf = realloc(en->buf, en->bufAlloced); | |
471 | if (en->resultPtr) *en->resultPtr = en->buf; | |
4d4a4e20 | 472 | memset(en->buf + en->bufAlloced - 20, 0, 20); |
6f481af2 | 473 | } |
474 | ||
4062a29f | 475 | if (en->cursorPosition != en->bufUsed) { |
6f481af2 | 476 | /* insert the new character */ |
4d4a4e20 | 477 | memmove(en->buf + en->cursorPosition + i, en->buf + en->cursorPosition, en->bufUsed - en->cursorPosition); |
6f481af2 | 478 | } |
4062a29f | 479 | en->bufUsed += i; |
480 | for (l = 0; l < i; l++) | |
481 | en->buf[en->cursorPosition++] = s[l]; | |
6f481af2 | 482 | } else { |
483 | er.result = ER_IGNORED; | |
484 | } | |
45f6c4fd | 485 | } |
6fb96a3f | 486 | |
4d4a4e20 | 487 | if (en->cursorPosition == en->bufUsed && en->cursorPosition && |
488 | !(en->flags & NEWT_FLAG_SCROLL || wstrlen(en->buf, -1) < co->width)) | |
489 | en->cursorPosition = previous_char(en->buf, en->cursorPosition); | |
490 | ||
6fb96a3f | 491 | entryDraw(co); |
492 | ||
493 | return er; | |
494 | } | |
fad2cd5f | 495 | |
496 | char * newtEntryGetValue(newtComponent co) { | |
497 | struct entry * en = co->data; | |
498 | ||
499 | return en->buf; | |
500 | } | |
501 | ||
502 | void newtEntrySetFilter(newtComponent co, newtEntryFilter filter, void * data) { | |
503 | struct entry * en = co->data; | |
504 | en->filter = filter; | |
505 | en->filterData = data; | |
506 | } | |
c8cddffd DW |
507 | |
508 | int newtEntryGetCursorPosition (newtComponent co) { | |
509 | struct entry * en = co->data; | |
510 | ||
511 | return en->cursorPosition; | |
512 | } | |
513 | ||
514 | void newtEntrySetCursorPosition (newtComponent co, int position) { | |
515 | struct entry * en = co->data; | |
516 | ||
517 | en->cursorPosition = position; | |
518 | } |