~ubuntu-branches/ubuntu/dapper/newt/dapper-security

« back to all changes in this revision

Viewing changes to textbox.c

  • Committer: Bazaar Package Importer
  • Author(s): Junichi Uekawa
  • Date: 2002-03-31 09:38:18 UTC
  • Revision ID: james.westby@ubuntu.com-20020331093818-t3cla7103r07qnyw
Tags: upstream-0.50.17
ImportĀ upstreamĀ versionĀ 0.50.17

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <ctype.h>
 
2
#include <slang.h>
 
3
#include <stdlib.h>
 
4
#include <string.h>
 
5
 
 
6
#include "newt.h"
 
7
#include "newt_pr.h"
 
8
 
 
9
struct textbox {
 
10
    char ** lines;
 
11
    int numLines;
 
12
    int linesAlloced;
 
13
    int doWrap;
 
14
    newtComponent sb;
 
15
    int topLine;
 
16
    int textWidth;
 
17
};
 
18
 
 
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,
 
25
                                      struct event ev);
 
26
static void textboxDestroy(newtComponent co);
 
27
static void textboxPlace(newtComponent co, int newLeft, int newTop);
 
28
static void textboxMapped(newtComponent co, int isMapped);
 
29
 
 
30
static struct componentOps textboxOps = {
 
31
    textboxDraw,
 
32
    textboxEvent,
 
33
    textboxDestroy,
 
34
    textboxPlace,
 
35
    textboxMapped,
 
36
} ;
 
37
 
 
38
static void textboxMapped(newtComponent co, int isMapped) {
 
39
    struct textbox * tb = co->data;
 
40
 
 
41
    co->isMapped = isMapped;
 
42
    if (tb->sb)
 
43
        tb->sb->ops->mapped(tb->sb, isMapped);
 
44
}
 
45
 
 
46
static void textboxPlace(newtComponent co, int newLeft, int newTop) {
 
47
    struct textbox * tb = co->data;
 
48
 
 
49
    co->top = newTop;
 
50
    co->left = newLeft;
 
51
 
 
52
    if (tb->sb)
 
53
        tb->sb->ops->place(tb->sb, co->left + co->width - 1, co->top);
 
54
}
 
55
 
 
56
void newtTextboxSetHeight(newtComponent co, int height) {
 
57
    co->height = height;
 
58
}
 
59
 
 
60
int newtTextboxGetNumLines(newtComponent co) {
 
61
    struct textbox * tb = co->data;
 
62
 
 
63
    return (tb->numLines);
 
64
}
 
65
 
 
66
newtComponent newtTextboxReflowed(int left, int top, char * text, int width,
 
67
                                  int flexDown, int flexUp, int flags) {
 
68
    newtComponent co;
 
69
    char * reflowedText;
 
70
    int actWidth, actHeight;
 
71
 
 
72
    reflowedText = newtReflowText(text, width, flexDown, flexUp,
 
73
                                  &actWidth, &actHeight);
 
74
    
 
75
    co = newtTextbox(left, top, actWidth, actHeight, NEWT_FLAG_WRAP);
 
76
    newtTextboxSetText(co, reflowedText);
 
77
    free(reflowedText);
 
78
 
 
79
    return co;
 
80
}
 
81
 
 
82
newtComponent newtTextbox(int left, int top, int width, int height, int flags) {
 
83
    newtComponent co;
 
84
    struct textbox * tb;
 
85
 
 
86
    co = malloc(sizeof(*co));
 
87
    tb = malloc(sizeof(*tb));
 
88
    co->data = tb;
 
89
 
 
90
    co->ops = &textboxOps;
 
91
 
 
92
    co->height = height;
 
93
    co->top = top;
 
94
    co->left = left;
 
95
    co->takesFocus = 0;
 
96
    co->width = width;
 
97
 
 
98
    tb->doWrap = flags & NEWT_FLAG_WRAP;
 
99
    tb->numLines = 0;
 
100
    tb->linesAlloced = 0;
 
101
    tb->lines = NULL;
 
102
    tb->topLine = 0;
 
103
    tb->textWidth = width;
 
104
 
 
105
    if (flags & NEWT_FLAG_SCROLL) {
 
106
        co->width += 2;
 
107
        tb->sb = newtVerticalScrollbar(co->left + co->width - 1, co->top, 
 
108
                           co->height, COLORSET_TEXTBOX, COLORSET_TEXTBOX);
 
109
    } else {
 
110
        tb->sb = NULL;
 
111
    }
 
112
 
 
113
    return co;
 
114
}
 
115
 
 
116
static char * expandTabs(const char * text) {
 
117
    int bufAlloced = strlen(text) + 40;
 
118
    char * buf, * dest;
 
119
    const char * src;
 
120
    int bufUsed = 0;
 
121
    int linePos = 0;
 
122
    int i;
 
123
 
 
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;
 
130
        }
 
131
        if (*src == '\t') {
 
132
            i = 8 - (linePos & 8);
 
133
            memset(dest, ' ', i);
 
134
            dest += i, bufUsed += i, linePos += i;
 
135
        } else {
 
136
            if (*src == '\n')
 
137
                linePos = 0;
 
138
            else
 
139
                linePos++;
 
140
 
 
141
            *dest++ = *src;
 
142
            bufUsed++;
 
143
        }
 
144
    }
 
145
 
 
146
    *dest = '\0';
 
147
    return buf;
 
148
}
 
149
 
 
150
#define iseuckanji(c)   (0xa1 <= (unsigned char)(c&0xff) && (unsigned char)(c&0xff) <= 0xfe)
 
151
 
 
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;
 
156
    int i;
 
157
    int howbad = 0;
 
158
    int height = 0;
 
159
    int kanji = 0;
 
160
 
 
161
    if (resultPtr) {
 
162
        /* XXX I think this will work */
 
163
        result = malloc(strlen(text) + (strlen(text) / width) + 2);
 
164
        *result = '\0';
 
165
    }
 
166
    
 
167
    while (*text) {
 
168
        kanji = 0;
 
169
        end = strchr(text, '\n');
 
170
        if (!end)
 
171
            end = text + strlen(text);
 
172
 
 
173
        while (*text && text <= end) {
 
174
            if (end - text < width) {
 
175
                if (result) {
 
176
                    strncat(result, text, end - text);
 
177
                    strcat(result, "\n");
 
178
                    height++;
 
179
                }
 
180
 
 
181
                if (end - text < (width / 2))
 
182
                    howbad += ((width / 2) - (end - text)) / 2;
 
183
                text = end;
 
184
                if (*text) text++;
 
185
            } else {
 
186
                chptr = text;
 
187
                kanji = 0;
 
188
                for ( i = 0; i < width - 1; i++ ) {
 
189
                    if ( !iseuckanji(*chptr)) {
 
190
                        kanji = 0;
 
191
                    } else if ( kanji == 1 ) {
 
192
                        kanji = 2; 
 
193
                    } else {
 
194
                        kanji = 1;
 
195
                    }
 
196
                    chptr++;
 
197
                }
 
198
                if (kanji == 0) {
 
199
                    while (chptr > text && !isspace(*chptr)) chptr--;
 
200
                    while (chptr > text && isspace(*chptr)) chptr--;
 
201
                    chptr++;
 
202
                }
 
203
                
 
204
                if (chptr-text == 1 && !isspace(*chptr))
 
205
                  chptr = text + width - 1;
 
206
 
 
207
                if (chptr > text)
 
208
                    howbad += width - (chptr - text) + 1;
 
209
                if (result) {
 
210
                  if (kanji == 1) {
 
211
                    strncat(result, text, chptr - text + 1 );
 
212
                    chptr++;
 
213
                    kanji = 0;
 
214
                  } else {
 
215
                    strncat(result, text, chptr - text );
 
216
                  }
 
217
                    strcat(result, "\n");
 
218
                    height++;
 
219
                }
 
220
 
 
221
                if (isspace(*chptr))
 
222
                    text = chptr + 1;
 
223
                else
 
224
                  text = chptr;
 
225
                while (isspace(*text)) text++;
 
226
            }
 
227
        }
 
228
    }
 
229
 
 
230
    if (badness) *badness = howbad;
 
231
    if (resultPtr) *resultPtr = result;
 
232
    if (heightPtr) *heightPtr = height;
 
233
}
 
234
 
 
235
char * newtReflowText(char * text, int width, int flexDown, int flexUp,
 
236
                      int * actualWidth, int * actualHeight) {
 
237
    int min, max;
 
238
    int i;
 
239
    char * result;
 
240
    int minbad, minbadwidth, howbad;
 
241
    char * expandedText;
 
242
 
 
243
    expandedText = expandTabs(text);
 
244
 
 
245
    if (flexDown || flexUp) {
 
246
        min = width - flexDown;
 
247
        max = width + flexUp;
 
248
 
 
249
        minbad = -1;
 
250
        minbadwidth = width;
 
251
 
 
252
        for (i = min; i <= max; i++) {
 
253
            doReflow(expandedText, NULL, i, &howbad, NULL);
 
254
 
 
255
            if (minbad == -1 || howbad < minbad) {
 
256
                minbad = howbad;
 
257
                minbadwidth = i;
 
258
            }
 
259
        }
 
260
 
 
261
        width = minbadwidth;
 
262
    }
 
263
 
 
264
    doReflow(expandedText, &result, width, NULL, actualHeight);
 
265
    free(expandedText);
 
266
    if (actualWidth) *actualWidth = width;
 
267
    return result;
 
268
}
 
269
 
 
270
void newtTextboxSetText(newtComponent co, const char * text) {
 
271
    const char * start, * end;
 
272
    struct textbox * tb = co->data;
 
273
    char * reflowed, * expanded;
 
274
    int badness, height;
 
275
 
 
276
    if (tb->lines) {
 
277
        free(tb->lines);
 
278
        tb->linesAlloced = tb->numLines = 0;
 
279
    }
 
280
 
 
281
    expanded = expandTabs(text);
 
282
 
 
283
    if (tb->doWrap) {
 
284
        doReflow(expanded, &reflowed, tb->textWidth, &badness, &height);
 
285
        free(expanded);
 
286
        expanded = reflowed;
 
287
    }
 
288
 
 
289
    for (start = expanded; *start; start++)
 
290
        if (*start == '\n') tb->linesAlloced++;
 
291
 
 
292
    /* This ++ leaves room for an ending line w/o a \n */
 
293
    tb->linesAlloced++;
 
294
    tb->lines = malloc(sizeof(char *) * tb->linesAlloced);
 
295
 
 
296
    start = expanded;
 
297
    while ((end = strchr(start, '\n'))) {
 
298
        addLine(co, start, end - start);
 
299
        start = end + 1;
 
300
    }
 
301
 
 
302
    if (*start)
 
303
        addLine(co, start, strlen(start));
 
304
 
 
305
    free(expanded);
 
306
}
 
307
 
 
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;
 
311
 
 
312
    if (len > tb->textWidth) len = tb->textWidth;
 
313
 
 
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';
 
318
}
 
319
 
 
320
static void textboxDraw(newtComponent c) {
 
321
    int i;
 
322
    struct textbox * tb = c->data;
 
323
    int size;
 
324
 
 
325
    if (tb->sb) {
 
326
        size = tb->numLines - c->height;
 
327
        newtScrollbarSet(tb->sb, tb->topLine, size ? size : 0);
 
328
        tb->sb->ops->draw(tb->sb);
 
329
    }
 
330
 
 
331
    SLsmg_set_color(NEWT_COLORSET_TEXTBOX);
 
332
   
 
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]);
 
336
    }
 
337
}
 
338
 
 
339
static struct eventResult textboxEvent(newtComponent co, 
 
340
                                      struct event ev) {
 
341
    struct textbox * tb = co->data;
 
342
    struct eventResult er;
 
343
 
 
344
    er.result = ER_IGNORED;
 
345
 
 
346
    if (ev.when == EV_EARLY && ev.event == EV_KEYPRESS && tb->sb) {
 
347
        switch (ev.u.key) {
 
348
          case NEWT_KEY_UP:
 
349
            if (tb->topLine) tb->topLine--;
 
350
            textboxDraw(co);
 
351
            er.result = ER_SWALLOWED;
 
352
            break;
 
353
 
 
354
          case NEWT_KEY_DOWN:
 
355
            if (tb->topLine < (tb->numLines - co->height)) tb->topLine++;
 
356
            textboxDraw(co);
 
357
            er.result = ER_SWALLOWED;
 
358
            break;
 
359
 
 
360
          case NEWT_KEY_PGDN:
 
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;
 
365
            }
 
366
            textboxDraw(co);
 
367
            er.result = ER_SWALLOWED;
 
368
            break;
 
369
 
 
370
          case NEWT_KEY_PGUP:
 
371
            tb->topLine -= co->height;
 
372
            if (tb->topLine < 0) tb->topLine = 0;
 
373
            textboxDraw(co);
 
374
            er.result = ER_SWALLOWED;
 
375
            break;
 
376
        }
 
377
    }
 
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--;
 
382
            textboxDraw(co);
 
383
            
 
384
            er.result = ER_SWALLOWED;
 
385
        }
 
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++;
 
390
            textboxDraw(co);
 
391
            
 
392
            er.result = ER_SWALLOWED;
 
393
        }
 
394
    }
 
395
    return er;
 
396
}
 
397
 
 
398
static void textboxDestroy(newtComponent co) {
 
399
    int i;
 
400
    struct textbox * tb = co->data;
 
401
 
 
402
    for (i = 0; i < tb->numLines; i++) 
 
403
        free(tb->lines[i]);
 
404
    free(tb->lines);
 
405
    free(tb);
 
406
    free(co);
 
407
}