19
static char * expandTabs(const char * text);
20
static void textboxDraw(newtComponent co);
21
static void addLine(newtComponent co, const char * s, int len);
22
static void doReflow(const char * text, char ** resultPtr, int width,
23
int * badness, int * heightPtr);
24
static struct eventResult textboxEvent(newtComponent c,
26
static void textboxDestroy(newtComponent co);
27
static void textboxPlace(newtComponent co, int newLeft, int newTop);
28
static void textboxMapped(newtComponent co, int isMapped);
30
static struct componentOps textboxOps = {
38
static void textboxMapped(newtComponent co, int isMapped) {
39
struct textbox * tb = co->data;
41
co->isMapped = isMapped;
43
tb->sb->ops->mapped(tb->sb, isMapped);
46
static void textboxPlace(newtComponent co, int newLeft, int newTop) {
47
struct textbox * tb = co->data;
53
tb->sb->ops->place(tb->sb, co->left + co->width - 1, co->top);
56
void newtTextboxSetHeight(newtComponent co, int height) {
60
int newtTextboxGetNumLines(newtComponent co) {
61
struct textbox * tb = co->data;
63
return (tb->numLines);
66
newtComponent newtTextboxReflowed(int left, int top, char * text, int width,
67
int flexDown, int flexUp, int flags) {
70
int actWidth, actHeight;
72
reflowedText = newtReflowText(text, width, flexDown, flexUp,
73
&actWidth, &actHeight);
75
co = newtTextbox(left, top, actWidth, actHeight, NEWT_FLAG_WRAP);
76
newtTextboxSetText(co, reflowedText);
82
newtComponent newtTextbox(int left, int top, int width, int height, int flags) {
86
co = malloc(sizeof(*co));
87
tb = malloc(sizeof(*tb));
90
co->ops = &textboxOps;
98
tb->doWrap = flags & NEWT_FLAG_WRAP;
100
tb->linesAlloced = 0;
103
tb->textWidth = width;
105
if (flags & NEWT_FLAG_SCROLL) {
107
tb->sb = newtVerticalScrollbar(co->left + co->width - 1, co->top,
108
co->height, COLORSET_TEXTBOX, COLORSET_TEXTBOX);
116
static char * expandTabs(const char * text) {
117
int bufAlloced = strlen(text) + 40;
124
buf = malloc(bufAlloced + 1);
125
for (src = text, dest = buf; *src; src++) {
126
if ((bufUsed + 10) > bufAlloced) {
127
bufAlloced += strlen(text) / 2;
128
buf = realloc(buf, bufAlloced + 1);
129
dest = buf + bufUsed;
132
i = 8 - (linePos & 8);
133
memset(dest, ' ', i);
134
dest += i, bufUsed += i, linePos += i;
150
#define iseuckanji(c) (0xa1 <= (unsigned char)(c&0xff) && (unsigned char)(c&0xff) <= 0xfe)
152
static void doReflow(const char * text, char ** resultPtr, int width,
153
int * badness, int * heightPtr) {
154
char * result = NULL;
155
const char * chptr, * end;
162
/* XXX I think this will work */
163
result = malloc(strlen(text) + (strlen(text) / width) + 2);
169
end = strchr(text, '\n');
171
end = text + strlen(text);
173
while (*text && text <= end) {
174
if (end - text < width) {
176
strncat(result, text, end - text);
177
strcat(result, "\n");
181
if (end - text < (width / 2))
182
howbad += ((width / 2) - (end - text)) / 2;
188
for ( i = 0; i < width - 1; i++ ) {
189
if ( !iseuckanji(*chptr)) {
191
} else if ( kanji == 1 ) {
199
while (chptr > text && !isspace(*chptr)) chptr--;
200
while (chptr > text && isspace(*chptr)) chptr--;
204
if (chptr-text == 1 && !isspace(*chptr))
205
chptr = text + width - 1;
208
howbad += width - (chptr - text) + 1;
211
strncat(result, text, chptr - text + 1 );
215
strncat(result, text, chptr - text );
217
strcat(result, "\n");
225
while (isspace(*text)) text++;
230
if (badness) *badness = howbad;
231
if (resultPtr) *resultPtr = result;
232
if (heightPtr) *heightPtr = height;
235
char * newtReflowText(char * text, int width, int flexDown, int flexUp,
236
int * actualWidth, int * actualHeight) {
240
int minbad, minbadwidth, howbad;
243
expandedText = expandTabs(text);
245
if (flexDown || flexUp) {
246
min = width - flexDown;
247
max = width + flexUp;
252
for (i = min; i <= max; i++) {
253
doReflow(expandedText, NULL, i, &howbad, NULL);
255
if (minbad == -1 || howbad < minbad) {
264
doReflow(expandedText, &result, width, NULL, actualHeight);
266
if (actualWidth) *actualWidth = width;
270
void newtTextboxSetText(newtComponent co, const char * text) {
271
const char * start, * end;
272
struct textbox * tb = co->data;
273
char * reflowed, * expanded;
278
tb->linesAlloced = tb->numLines = 0;
281
expanded = expandTabs(text);
284
doReflow(expanded, &reflowed, tb->textWidth, &badness, &height);
289
for (start = expanded; *start; start++)
290
if (*start == '\n') tb->linesAlloced++;
292
/* This ++ leaves room for an ending line w/o a \n */
294
tb->lines = malloc(sizeof(char *) * tb->linesAlloced);
297
while ((end = strchr(start, '\n'))) {
298
addLine(co, start, end - start);
303
addLine(co, start, strlen(start));
308
/* This assumes the buffer is allocated properly! */
309
static void addLine(newtComponent co, const char * s, int len) {
310
struct textbox * tb = co->data;
312
if (len > tb->textWidth) len = tb->textWidth;
314
tb->lines[tb->numLines] = malloc(tb->textWidth + 1);
315
memset(tb->lines[tb->numLines], ' ', tb->textWidth);
316
memcpy(tb->lines[tb->numLines], s, len);
317
tb->lines[tb->numLines++][tb->textWidth] = '\0';
320
static void textboxDraw(newtComponent c) {
322
struct textbox * tb = c->data;
326
size = tb->numLines - c->height;
327
newtScrollbarSet(tb->sb, tb->topLine, size ? size : 0);
328
tb->sb->ops->draw(tb->sb);
331
SLsmg_set_color(NEWT_COLORSET_TEXTBOX);
333
for (i = 0; (i + tb->topLine) < tb->numLines && i < c->height; i++) {
334
newtGotorc(c->top + i, c->left);
335
SLsmg_write_string(tb->lines[i + tb->topLine]);
339
static struct eventResult textboxEvent(newtComponent co,
341
struct textbox * tb = co->data;
342
struct eventResult er;
344
er.result = ER_IGNORED;
346
if (ev.when == EV_EARLY && ev.event == EV_KEYPRESS && tb->sb) {
349
if (tb->topLine) tb->topLine--;
351
er.result = ER_SWALLOWED;
355
if (tb->topLine < (tb->numLines - co->height)) tb->topLine++;
357
er.result = ER_SWALLOWED;
361
tb->topLine += co->height;
362
if (tb->topLine > (tb->numLines - co->height)) {
363
tb->topLine = tb->numLines - co->height;
364
if (tb->topLine < 0) tb->topLine = 0;
367
er.result = ER_SWALLOWED;
371
tb->topLine -= co->height;
372
if (tb->topLine < 0) tb->topLine = 0;
374
er.result = ER_SWALLOWED;
378
if (ev.when == EV_EARLY && ev.event == EV_MOUSE && tb->sb) {
379
/* Top scroll arrow */
380
if (ev.u.mouse.x == co->width && ev.u.mouse.y == co->top) {
381
if (tb->topLine) tb->topLine--;
384
er.result = ER_SWALLOWED;
386
/* Bottom scroll arrow */
387
if (ev.u.mouse.x == co->width &&
388
ev.u.mouse.y == co->top + co->height - 1) {
389
if (tb->topLine < (tb->numLines - co->height)) tb->topLine++;
392
er.result = ER_SWALLOWED;
398
static void textboxDestroy(newtComponent co) {
400
struct textbox * tb = co->data;
402
for (i = 0; i < tb->numLines; i++)