1 /*
2
3 Copyright (C) 2015-2018 Night Dive Studios, LLC.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 */
19 /*
20 * the texttool, a generic text editor shell sort of thing
21 * only infinitely lamer
22 */
23
24
25 #include <string.h>
26 #include <stdio.h>
27 #include <ctype.h>
28
29 #include "lg.h"
30 //#include <mprintf.h>
31 #include "texttool.h"
32 #include <stdlib.h> // malloc(), free()
33
34 #define _tt_top(tid) if (tid==NULL) tid=cur_tt; _tt=tid;
35
36 #define StrDraw _tt->lfont->s_draw
37 #define CharDraw _tt->lfont->c_draw
38 #define StrWid _tt->lfont->s_wid
39 #define CharWid _tt->lfont->c_wid
40 #define LenClr _tt->lfont->l_clr
41 #define CharClr _tt->lfont->c_clr
42 #define StrClr _tt->lfont->s_clr
43 #define LGCursor _tt->lfont->cursor
44
45 #define LineExist(_lt,lnum) ((lnum>=0)&&(lnum<_lt->max_h)&&(_lt->lines[lnum]!=NULL))
46 #define LastChar(_lt,lnum) (_lt->lines[lnum][_lt->line_info[lnum].stl-1])
47
48 // internal prototypes
49 void _tt_build_cheat(long line_num);
50 void _tt_new_line(long line_num);
51 //TextTool *tt_full_build(TTRect *pos, TTState *es, TTFontInfo *ttf, void *output_data, char *keymap, void *(d_func)(void *, LGRect *));
52 void tt_resize(TextTool *tt, int wid, int height);
53 void _tt_display_line(long line_num, long p_left, long p_right);
54 void _tt_show_line(long line_num, long p_left, long p_right);
55 int _tt_word_len(int which_word, char *s, long pos);
56 void _tt_resize_line(long line_num, long new_len);
57 void _tt_break_line(long line_num, long break_pt);
58 void _tt_rem_front(long line_num, long rem_pos);
59 void _tt_rem_mid(long line_num, long left_c, long right_c);
60 uchar _tt_wrap_check(long *line_num, long *cur_pos);
61 uchar _tt_add_char(long *line_num, long *cur_pos, char c);
62 uchar _tt_del_chars(long *line_num, long *cur_pos, int cnt);
63 uchar _tt_chg_line(int how);
64 uchar _tt_chg_colu(int how);
65 void _tt_return(void);
66 ulong _tt_check_cursor_position(void);
67 int _tt_do_event(long tt_event);
68
69 // static local coolness
70 static TextTool *cur_tt=NULL, *_tt=NULL;
71
72 // Must choose one of these font headers to actually use.... and then, of course
73 // make sure you link appropriately also. Is there a more graceful way to deal?
74 // #include <monofont.h>
75 // #include <realfont.h>
76 #include "tngfont.h"
77 #include "fakefont.h"
78
79 static TTRect TTDefRect = {{0,0},80,24};
80 static TTState TTDefState = {0,66,0,TTS_WRAP|TTS_FULL,1,TTEV_NULL};
81 //static TTFontInfo TTDefFont =
82 // {mono_s_wid, mono_s_draw, mono_c_wid, mono_c_draw, mono_s_clr, mono_l_clr, mono_c_clr, mono_cursor, 1, 1, TTFI_FIXED };
83 //static TTKeyMap TTDefKMap;
84
85 TTFontInfo TTDefFont =
86 {fnt_s_width, fnt_s_draw, fnt_c_width, fnt_c_draw, fnt_s_clr, fnt_l_clr, fnt_c_clr, fnt_cursor, 7, 7, TTFI_PROP|TTFI_SPACE };
87
88
89
90 // public useful stuff
tt_full_build(TTRect * pos,TTState * es,TTFontInfo * ttf,void * output_data,char * keymap,void (* d_func)(void *,LGRect *))91 TextTool *tt_full_build(TTRect *pos, TTState *es, TTFontInfo *ttf, void *output_data, char *keymap, void (*d_func)(void *, LGRect *))
92 {
93 TextTool *new_tt;
94 char *dummy;
95 dummy = keymap;
96
97 new_tt=(TextTool *)malloc(sizeof(TextTool));
98 _tt_top(new_tt);
99 _tt->max_w=_tt->max_h=_tt->cur_w=_tt->cur_h=0;
100 if (pos!=NULL) _tt->scr_loc=*pos;
101 else _tt->scr_loc=TTDefRect;
102 _tt->disp_x=_tt->disp_y=0; // focus on upper left corner
103 if (ttf!=NULL) _tt->lfont=ttf;
104 else _tt->lfont=&TTDefFont;
105 _tt->output_data = output_data;
106 _tt->display_func = d_func;
107 _tt->lines=(char **)malloc(1);
108 _tt->line_info=(TTCheats *)malloc(1);
109 _tt->disp_rows=(_tt->scr_loc.h+_tt->lfont->height-1)/_tt->lfont->height;
110 _tt_new_line(0);
111 if (es!=NULL) _tt->es=*es;
112 else _tt->es=TTDefState;
113 return new_tt;
114 }
115
tt_toast(TextTool * old_tt)116 uchar tt_toast(TextTool *old_tt)
117 {
118 int i;
119 for (i=0; i<old_tt->max_h; i++)
120 free(old_tt->lines[i]);
121 free(*(old_tt->lines));
122 free(old_tt->line_info);
123 return TRUE;
124 }
125
126 // set this tt to be the default one
tt_set(TextTool * def_tt)127 uchar tt_set(TextTool *def_tt)
128 {
129 cur_tt=def_tt;
130 return TRUE;
131 }
132
tt_move(TextTool * tt,int xoff,int yoff)133 void tt_move(TextTool *tt, int xoff, int yoff)
134 {
135 _tt_top(tt);
136 _tt->scr_loc.crn.pt.x=xoff; _tt->scr_loc.crn.pt.y=yoff;
137 }
138
tt_resize(TextTool * tt,int wid,int height)139 void tt_resize(TextTool *tt, int wid, int height)
140 {
141 _tt_top(tt);
142 _tt->scr_loc.w=wid; _tt->scr_loc.h=height;
143 // do stuff here... recompute the universe, etc...
144 }
145
146 // move to a new line
147 // delete a line
148
149 // build a cheat for one line
_tt_build_cheat(long line_num)150 void _tt_build_cheat(long line_num)
151 {
152 TTCheats *loc=&(_tt->line_info[line_num]);
153 int x_pix=0, x_chr=0, a_wid;
154 char *sb=_tt->lines[line_num], *s;
155
156 // recheck carefully for proportional font stuff...
157 // should probably modularize out the selector for optimal expose events
158
159 a_wid=strlen(s=sb);
160 loc->stl=a_wid;
161 // find the left edge
162 while ((x_pix<_tt->disp_x)&&(x_chr<loc->stl))
163 { x_pix+=CharWid(*s++); x_chr++; }
164 if (x_chr==loc->stl)
165 { loc->chr[0]=TTC_NOTHING; loc->chr[1]=0; loc->pix[0]=0; loc->pix[1]=0; return; }
166 if (x_pix>_tt->disp_x)
167 { x_pix-=CharWid(*--s); --x_chr; }
168 loc->chr[0]=x_chr; loc->pix[0]=x_pix;
169 // find right edge
170
171 // bug if string width is 1, basically
172
173 x_pix+=CharWid(*s++); x_chr++;
174 while ((x_pix<_tt->disp_x+_tt->scr_loc.w)&&(x_chr<loc->stl))
175 { x_pix+=CharWid(*s++); x_chr++; }
176 if (x_chr==loc->stl)
177 { x_pix-=CharWid(*--s); --x_chr; }
178 loc->chr[1]=x_chr; loc->pix[1]=x_pix;
179
180 // mprintf("line %d (%s): cheat %d %d, %d %d\n",line_num,sb,loc->chr[0],loc->pix[0],loc->chr[1],loc->pix[1]);
181 }
182
183 // inserts a new line at line_num, inserts appropriately if necessary
_tt_new_line(long line_num)184 void _tt_new_line(long line_num)
185 {
186 _tt->max_h++;
187 //¥¥¥ _tt->lines=(char **)Realloc(_tt->lines,sizeof(char *)*_tt->max_h);
188 //¥¥¥ _tt->line_info=(TTCheats *)Realloc(_tt->line_info,sizeof(TTCheats)*_tt->max_h);
189 free(_tt->lines);
190 _tt->lines = (char **)malloc(sizeof(char *)*_tt->max_h);
191 free(_tt->line_info);
192 _tt->line_info = (TTCheats *)malloc(sizeof(TTCheats)*_tt->max_h);
193 if (line_num<_tt->max_h-1) /* insert case */
194 {
195 LG_memmove(&_tt->line_info[line_num+1],&_tt->line_info[line_num],sizeof(TTCheats)*(_tt->max_h-line_num-1));
196 LG_memmove(&_tt->lines[line_num+1],&_tt->lines[line_num],sizeof(char *)*(_tt->max_h-line_num-1));
197 }
198 _tt->line_info[line_num].wid=TTL_INIT; /* totally empty at first */
199 _tt->line_info[line_num].flg|=TTC_FLG_RET; /* should be a return there */
200 _tt->lines[line_num]=(char *)malloc(TTL_INIT); /* and it is empty (\0) */
201 _tt->lines[line_num][0]='\0';
202 _tt_build_cheat(line_num); /* so we need a cheat for it */
203 }
204
205 #ifdef MOO
206 // returns whether there are characters on the line in the specified range
207 // sets c_l and c_r to the character counts for the pix counts in p_l and p_r
208 // based on the string in l_n
_tt_pix_cnv(long l_n,long p_l,long p_r,long * c_l,long * c_r)209 uchar _tt_pix_cnv(long l_n, long p_l, long p_r, long *c_l, long *c_r)
210 {
211
212
213 }
214 #endif
215
216 // rebuild a range of cheats
217
218 // display one line starting at some coordinate
219 // display a rectangle of the area
220
221 // do appropriate gadgety things to display the line.
_tt_display_line(long line_num,long p_left,long p_right)222 void _tt_display_line(long line_num, long p_left, long p_right)
223 {
224 LGRect disp_rect;
225 int llin;
226
227 long dummy;
228 dummy = p_left;
229 dummy = p_right;
230
231 llin=line_num-_tt->disp_y;
232 disp_rect.ul.x = _tt->scr_loc.crn.pt.x+_tt->line_info[line_num].pix[0];
233 disp_rect.ul.y = _tt->scr_loc.crn.pt.y+llin*_tt->lfont->height;
234 disp_rect.lr.x = _tt->scr_loc.w - 1;
235 disp_rect.lr.y = disp_rect.ul.y + _tt->lfont->height;
236 // mprintf ("disp_rect = (%d, %d)(%d, %d)\n",disp_rect.ul.x, disp_rect.ul.y, disp_rect.lr.x, disp_rect.lr.y);
237 tt_display_all(_tt, &disp_rect);
238 }
239
240 // for real, display a partial (or full) line
_tt_show_line(long line_num,long p_left,long p_right)241 void _tt_show_line(long line_num, long p_left, long p_right)
242 {
243 int llin=line_num-_tt->disp_y, cy=line_num;
244 // long c_left, c_right;
245 uchar blnk_line=TRUE;
246
247 if ((line_num<_tt->disp_y)||(line_num>=_tt->disp_y+_tt->disp_rows)) return;
248 if (p_left==-1) p_left=0; if (p_right==-1) p_right=_tt->scr_loc.w-1;
249 if (LineExist(_tt,cy))
250 {
251 if (_tt->line_info[cy].chr[0]==TTC_REBUILD)
252 _tt_build_cheat(cy);
253 #ifdef LOUD
254 mono_setxy(60,llin);
255 mprintf("%2.2d %2.2d %2.2d %2.2d ",
256 _tt->line_info[cy].chr[0],_tt->line_info[cy].chr[1],_tt->line_info[cy].wid,_tt->line_info[cy].stl);
257 #endif
258 // _tt_pix_cnv(_tt->lines[cy],p_left,p_right,&c_left,&c_right);
259 if (_tt->line_info[cy].chr[0]!=TTC_NOTHING)
260 {
261 char *st_base, *s, c;
262 long wid;
263
264 st_base=_tt->lines[cy];
265 s=st_base+_tt->line_info[cy].chr[1]+1;
266 c=*s; *s='\0';
267 wid=StrDraw(st_base+_tt->line_info[cy].chr[0],
268 _tt->scr_loc.crn.pt.x+_tt->line_info[cy].pix[0],
269 _tt->scr_loc.crn.pt.y+llin*_tt->lfont->height);
270 *s=c; blnk_line=FALSE;
271 if (p_left+wid<p_right)
272 LenClr(p_right-p_left-wid,_tt->scr_loc.crn.pt.x+wid,_tt->scr_loc.crn.pt.y+llin*_tt->lfont->height);
273 }
274 }
275 if (blnk_line) LenClr(p_right-p_left,_tt->scr_loc.crn.pt.x,_tt->scr_loc.crn.pt.y+llin*_tt->lfont->height);
276 }
277
278 // do appropriate UI things to display the whole thing
tt_display_all(TextTool * tt,LGRect * r)279 void tt_display_all(TextTool *tt, LGRect *r)
280 {
281 if (tt->display_func != NULL)
282 tt->display_func(tt->output_data, r);
283 }
284
285 // fpr real, send full screen to output
tt_show_all(TextTool * tt)286 void tt_show_all(TextTool *tt)
287 {
288 long ay;
289 _tt_top(tt);
290 for (ay=0; ay<_tt->disp_rows; ay++)
291 _tt_show_line(ay+_tt->disp_y,-1,-1);
292 LGCursor(_tt->scr_loc.crn.pt.x+_tt->cur_w,_tt->scr_loc.crn.pt.y+_tt->cur_h-_tt->disp_y);
293 }
294
tt_dump(TextTool * tt)295 void tt_dump(TextTool *tt)
296 {
297 long ay;
298 _tt_top(tt);
299 printf("DUMP:\n");
300 for (ay=0; ay<_tt->max_h; ay++)
301 printf("%5.5ld %s\n", ay, _tt->lines[ay]);
302 }
303
304 // return the length of which_word (see defines TTWL_?) in char *s
_tt_word_len(int which_word,char * s,long pos)305 int _tt_word_len(int which_word, char *s, long pos)
306 {
307 char *p, *q, sw;
308 int val=-1; /* so we can see if this is acting way zany */
309
310 switch (which_word)
311 {
312 case TTWL_FIRST: p=strchr(s,' '); if (p==NULL) val=strlen(s); else val=p-s; break;
313 case TTWL_LAST: p=strrchr(s,' '); if (p==NULL) val=strlen(s); else val=s-p; break;
314 case TTWL_CUR: q=strchr(s+pos,' '); sw=*(s+pos); *(s+pos)='\0'; p=strrchr(s,' '); *(s+pos)=sw;
315 if ((q==NULL)&&(p==NULL)) val=strlen(s);
316 else if (q==NULL) val=strlen(s)-(p-s);
317 else if (p==NULL) val=q-s; else val=q-p; break;
318 }
319 return val;
320 }
321
_tt_resize_line(long line_num,long new_len)322 void _tt_resize_line(long line_num, long new_len)
323 {
324 long cur_len=_tt->line_info[line_num].wid;
325 long n_num, new_targ;
326
327 new_len+=2; // \0 and pad space
328 n_num=(new_len-TTL_INIT)/TTL_BASE; // num of chunks
329 if (((new_len-TTL_INIT)%TTL_BASE)!=0) n_num++;
330 new_targ=n_num*TTL_BASE+TTL_INIT;
331 if (new_targ==cur_len) return;
332 _tt->line_info[line_num].wid=new_targ;
333 //¥¥¥ _tt->lines[line_num]=Realloc(_tt->lines[line_num],new_targ);
334 //SetPtrSize((Ptr)_tt->lines[line_num],new_targ);
335 }
336
337 // fills line_num with s
tt_fill_line(TextTool * tt,int how,long line_num,char * s)338 void tt_fill_line(TextTool *tt, int how, long line_num, char *s)
339 {
340 long r_len=strlen(s), loop;
341 _tt_top(tt);
342 if (line_num>=_tt->max_h)
343 for (loop=_tt->max_h; loop<=line_num; loop++)
344 _tt_new_line(loop);
345 else
346 if (how==TTF_INSWHOLE) _tt_new_line(line_num); /* insert a new line */
347 if ((how==TTF_INSEND)||(how==TTF_INSFRONT))
348 {
349 if (_tt->line_info[line_num].stl>0)
350 r_len+=_tt->line_info[line_num].stl+2; /* +2 for the space and the \0 */
351 else
352 how=TTF_INSWHOLE; /* if nothing there, simply replace */
353 }
354 _tt_resize_line(line_num,r_len);
355 switch (how)
356 {
357 case TTF_REPLACE:
358 case TTF_INSWHOLE: strcpy(_tt->lines[line_num],s); break;
359 case TTF_INSEND: strcat(_tt->lines[line_num],s); break;
360 case TTF_INSFRONT:
361 LG_memmove(_tt->lines[line_num]+strlen(s)+1,_tt->lines[line_num],_tt->line_info[line_num].stl+1);
362 LG_memmove(_tt->lines[line_num],s,strlen(s)); /* dont need this \0 */
363 _tt->lines[line_num][strlen(s)]=' ';
364 break;
365 }
366 _tt_build_cheat(line_num);
367 _tt_display_line(line_num,-1,-1);
368
369 // should get gnosis of returns
370 }
371
372 // breaks off the first break_pt characters of line_num
_tt_break_line(long line_num,long break_pt)373 void _tt_break_line(long line_num, long break_pt)
374 {
375 if (break_pt>=_tt->line_info[line_num].stl) return;
376 _tt->lines[line_num][break_pt]='\0';
377 _tt_resize_line(line_num,break_pt);
378 _tt_build_cheat(line_num);
379 _tt_display_line(line_num,-1,-1);
380 }
381
_tt_rem_front(long line_num,long rem_pos)382 void _tt_rem_front(long line_num, long rem_pos)
383 {
384 int lin_len=_tt->line_info[line_num].stl;
385 if (rem_pos>=lin_len) return;
386 LG_memmove(_tt->lines[line_num],_tt->lines[line_num]+rem_pos, lin_len-rem_pos);
387 _tt_resize_line(line_num,lin_len-rem_pos+1);
388 _tt_build_cheat(line_num);
389 _tt_display_line(line_num,-1,-1);
390 }
391
_tt_rem_mid(long line_num,long left_c,long right_c)392 void _tt_rem_mid(long line_num, long left_c, long right_c)
393 {
394 int lin_len=_tt->line_info[line_num].stl, rem_cnt=right_c-left_c+1;
395 if ((rem_cnt>=lin_len)||(left_c>right_c)) return;
396 LG_memmove(_tt->lines[line_num]+left_c,_tt->lines[line_num]+right_c, lin_len-right_c);
397 _tt_resize_line(line_num,lin_len-rem_cnt);
398 _tt_build_cheat(line_num);
399 _tt_display_line(line_num,-1,-1);
400 }
401
402 // given that only line line_num changed, do wrap checks
_tt_wrap_check(long * line_num,long * cur_pos)403 uchar _tt_wrap_check(long *line_num, long *cur_pos)
404 {
405 char *s, *p, sw=0; /* pointers for manipulation, sw is the swap character */
406 long ln=*line_num;
407 uchar wr=FALSE;
408 // first, do we wrap back to the last line (should use pixwid, not stl)
409 if (LineExist(_tt,ln-1)&&((_tt->line_info[ln-1].flg&TTC_FLG_RET)==0))
410 if (_tt->line_info[ln-1].stl+1+_tt_word_len(TTWL_FIRST,_tt->lines[ln],0)<_tt->es.right_m)
411 printf("Wrap back - note %ld %d\n",_tt->line_info[ln-1].stl,_tt_word_len(TTWL_FIRST,_tt->lines[ln],0));
412 // now, does our line wrap
413 if (_tt->line_info[ln].stl>=_tt->es.right_m)
414 {
415 char *base=_tt->lines[ln];
416 s=strrchr(base,' ');
417 while ((s>base)&&(s-base>=_tt->es.right_m))
418 {
419 if (sw!=0) *p=sw; /* put the savechar back */
420 p=s; sw=*p; *p='\0'; s=strrchr(base,' '); /* go back another word */
421 }
422 if (sw!=0) *p=sw; /* put any punted characters back */
423 if (s>base)
424 { /* do the wrap */
425 int brk=(++s)-base; /* skip the space, figure out where to break */
426 printf("Want to wrap -%s-...",s);
427 tt_fill_line(NULL,TTF_INSFRONT,ln+1,s);
428 _tt_break_line(ln,brk-1);
429 _tt->line_info[ln].flg&=(~TTC_FLG_RET); /* punt the return */
430 printf("Note strlen %lu and stl %ld for .%s./.%s.\n",strlen(s),_tt->line_info[(*line_num)+1].stl,s,_tt->lines[(*line_num)+1]);
431 if ((*cur_pos)>brk)
432 { (*line_num)++; (*cur_pos)-=brk; }
433 wr=TRUE;
434 }
435 }
436 // now, should we bring something in from the next line, and propagate down
437 // send back ok error code
438 return wr;
439 }
440
441 // currently returns whether the line wrapped? why? who knows.
_tt_add_char(long * line_num,long * cur_pos,char c)442 uchar _tt_add_char(long *line_num, long *cur_pos, char c)
443 {
444 long new_stl=_tt->line_info[*line_num].stl, new_pos=*cur_pos;
445 char *s=_tt->lines[*line_num];
446 uchar add_at_end=TRUE;
447
448 if (new_stl>*cur_pos) { // insert
449 if ((_tt->es.mode&TTS_OVER)==0) // actually have to insert
450 LG_memmove(&s[*(cur_pos)+1],&s[*cur_pos],new_stl-*cur_pos);
451 else
452 add_at_end=FALSE; // just a punch in
453 }
454 if (add_at_end&&(_tt->es.max_w>0)&&(new_stl>=_tt->es.max_w))
455 new_stl--; // punt final character, we are out of space
456 if (add_at_end)
457 { s[*cur_pos]=c; c=0; new_pos=_tt->line_info[*line_num].stl=++new_stl; }
458 if (new_stl>_tt->line_info[*line_num].wid-2) // have to get more memory
459 _tt_resize_line(*line_num,new_stl);
460 if (new_stl>_tt->max_w) _tt->max_w=new_stl;
461 _tt->lines[*line_num][new_pos]=c; // put us down, R2
462 (*cur_pos)++; // go to next character
463 _tt_build_cheat(*line_num); // we can do incremental cheats later
464 if (_tt->es.mode&TTS_WRAP)
465 if (_tt_wrap_check(line_num,cur_pos)) return TRUE;
466 _tt_display_line(*line_num,-1,-1);
467 return FALSE;
468 }
469
470 // learn this about return flag
_tt_del_chars(long * line_num,long * cur_pos,int cnt)471 uchar _tt_del_chars(long *line_num, long *cur_pos, int cnt)
472 {
473 int lin_wid=_tt->line_info[*line_num].stl, nlpos=*cur_pos, nrpos=*cur_pos;
474 // int dir;
475 char *s=_tt->lines[*line_num];
476
477 if (cnt<0) nlpos+=cnt; else nrpos+=cnt;
478 if ((nlpos>=0)&&(nrpos<=lin_wid))
479 { /* easy case... all on the line */
480 LG_memmove(s+nlpos,s+nrpos,lin_wid-nrpos+1);
481 _tt->line_info[*line_num].stl-=cnt;
482 *cur_pos=nlpos;
483 _tt_display_line(*line_num,-1,-1);
484 _tt_build_cheat(*line_num);
485 }
486 else
487 { /* ugly scene, multi-line thingy */
488 printf("Unhappy %d %d.. %d f %d\n",nlpos,nrpos,lin_wid,cnt);
489
490 // cnt+=_tt->cur_w;
491 // if (cnt>0) { cnt-=lin_wid; dir=1; } else dir=-1;
492 // _tt_chg_line(dir);
493 // if (cnt>0) _tt->cur_w=0; else _tt->cur_w=_tt->line_info[_tt->cur_h].stl;
494 // _tt_chg_colu(cnt-dir); /* extra bonus wrap character there... */
495 }
496 return TRUE;
497 }
498
499 // return TRUE if we are out of space
_tt_chg_line(int how)500 uchar _tt_chg_line(int how)
501 {
502 uchar edge=FALSE; /* edge of available space */
503 how+=_tt->cur_h;
504 if (how<0) { _tt->cur_h=0; edge=TRUE; }
505 else if (how>=_tt->max_h)
506 {
507 if (_tt->es.mode&TTS_CGROW)
508 {
509 for (_tt->cur_h=_tt->max_h; _tt->cur_h<=how; _tt->cur_h++)
510 _tt_new_line(_tt->cur_h);
511 _tt->cur_w=0; _tt->cur_h--; // back to the last line
512 }
513 else
514 { edge=TRUE; _tt->cur_h=_tt->max_h-1; }
515 }
516 else
517 {
518 _tt->cur_h=how;
519 if (_tt->cur_w>=_tt->line_info[how].stl)
520 _tt->cur_w=_tt->line_info[how].stl;
521 }
522 return edge;
523 }
524
525 // returns if it hit the edge
_tt_chg_colu(int how)526 uchar _tt_chg_colu(int how)
527 {
528 int dir, ncpos=_tt->cur_w+how, lin_wid=_tt->line_info[_tt->cur_h].stl;
529
530 if ((ncpos>=0)&&(ncpos<=lin_wid))
531 _tt->cur_w=ncpos;
532 else
533 {
534 how+=_tt->cur_w;
535 if (how>0) { how-=lin_wid; dir=1; } else dir=-1;
536 if (_tt_chg_line(dir))
537 { if (dir>0) _tt->cur_w=_tt->line_info[_tt->cur_h].stl; else _tt->cur_w=0; return TRUE; }
538 if (how>0) _tt->cur_w=0; else _tt->cur_w=_tt->line_info[_tt->cur_h].stl;
539 _tt_chg_colu(how-dir); /* extra bonus wrap character there... */
540 }
541 return FALSE;
542 }
543
544 // should wrap to the next line
_tt_return(void)545 void _tt_return(void)
546 {
547 uchar line_gen=FALSE;
548
549
550 switch (_tt->es.mode&TTS_MODE)
551 {
552 case TTS_FULL:
553 _tt->line_info[_tt->cur_h].flg|=TTC_FLG_RET;
554 if (_tt->cur_w<_tt->line_info[_tt->cur_h].stl)
555 {
556 tt_fill_line(NULL,TTF_INSWHOLE,_tt->cur_h+1,_tt->lines[_tt->cur_h]+_tt->cur_w);
557 _tt_break_line(_tt->cur_h,_tt->cur_w);
558 line_gen=TRUE;
559 }
560 _tt->cur_h++; _tt->cur_w=0; /* go to beginning of next line */
561 if ((!line_gen)&&((_tt->es.mode&(TTS_OVER|TTS_READONLY))==0))
562 _tt_new_line(_tt->cur_h);
563 break;
564 case TTS_SINGLE:
565 case TTS_LINES:
566 case TTS_READONLY:
567 break;
568 }
569 }
570
571 // returns changes based on _tt->cur_w and h in terms of scrolling and such
_tt_check_cursor_position(void)572 ulong _tt_check_cursor_position(void)
573 {
574 ulong changed=0;
575 if (_tt->cur_h<_tt->disp_y) /* cursor off top of screen */
576 { _tt->disp_y=_tt->cur_h; changed|=TTCHG_REDRAW; } /* focus up there */
577 if (_tt->cur_h>=_tt->disp_y+_tt->disp_rows)
578 { _tt->disp_y=_tt->cur_h-_tt->disp_rows+1; changed|=TTCHG_REDRAW; }
579 changed|=TTCHG_CURSOR; // since mono_font has to keep moving it around all the time
580 return changed;
581 }
582
583 // actually does things. This takes events, which can come out of script files, macros, or keystroke parses
_tt_do_event(long tt_event)584 int _tt_do_event(long tt_event)
585 {
586 // int old_w=_tt->cur_w, old_h=_tt->cur_h;
587 int changed=0;
588
589 if (tt_event&_ALL_M)
590 {
591 if ((tt_event&(_tt->es.mode&_ALL_M))==0) /* is not an event in this mode */
592 tt_event=TTEV_NULL;
593
594 switch (tt_event)
595 {
596 case TTEV_RET: _tt_return(); break;
597 case TTEV_F_CHAR: _tt_chg_colu( _tt->es.r_cnt); break;
598 case TTEV_B_CHAR: _tt_chg_colu(-_tt->es.r_cnt); break;
599 case TTEV_F_LINE: _tt_chg_line( _tt->es.r_cnt); break;
600 case TTEV_B_LINE: _tt_chg_line(-_tt->es.r_cnt); break;
601 case TTEV_REPEAT: _tt->es.r_cnt*=4; break;
602 case TTEV_DEL: _tt_del_chars(&_tt->cur_h, &_tt->cur_w, _tt->es.r_cnt); break;
603 case TTEV_BACKSP: _tt_del_chars(&_tt->cur_h, &_tt->cur_w,-_tt->es.r_cnt); break;
604 case TTEV_KILL: _tt_break_line(_tt->cur_h, _tt->cur_w); break;
605 case TTEV_HOME:
606 case TTEV_BOL: _tt->cur_w=0; break;
607 case TTEV_END:
608 case TTEV_EOL: _tt->cur_w=_tt->line_info[_tt->cur_h].stl; break;
609 case TTEV_OVER: if (_tt->es.mode&TTS_OVER) _tt->es.mode-=TTS_OVER; else _tt->es.mode+=TTS_OVER; break;
610 case TTEV_WRAP: if (_tt->es.mode&TTS_WRAP) _tt->es.mode-=TTS_WRAP; else _tt->es.mode+=TTS_WRAP; break;
611 case TTEV_NULL: break;
612 } // life is short and love is always over in the morning black wind come carry me far away
613 }
614 else /* normal key */
615 {
616 if (_tt->es.mode&TTS_READONLY) return TTCHG_NOCHANGE; /* readonly mode, ignore non-event keys */
617 _tt_add_char(&_tt->cur_h,&_tt->cur_w,tt_event);
618 // _tt_chg_line(1);
619 // else
620 // _tt_chg_colu(1);
621 }
622 if ((_tt->es.r_cnt!=1)&&(tt_event!=TTEV_REPEAT))
623 _tt->es.r_cnt=1; /* reset extra count */
624 // if ((old_w!=_tt->cur_w)||(old_h!=_tt->cur_h)) changed|=TTCHG_CURSOR;
625 changed|=_tt_check_cursor_position();
626 _tt->es.last_ev=tt_event;
627 return changed;
628 }
629
630 // converts an input character into an event for the tt system
631 // returns -1 or the line selected (w/return)
tt_parse_char(TextTool * tt,ushort key_code)632 long tt_parse_char(TextTool *tt, ushort key_code)
633 {
634 char c = (key_code & 0xFF);
635 int ret;
636 int event = TTEV_NULL;
637 _tt_top(tt);
638
639 if (key_code & TEXTTOOL_KB_FLAG_CTRL)
640 {
641 switch (c)
642 {
643 case 'a': event=TTEV_BOL; break;
644 case 'b': event=TTEV_B_CHAR; break;
645 case 'd': event=TTEV_DEL; break;
646 case 'e': event=TTEV_EOL; break;
647 case 'f': event=TTEV_F_CHAR; break;
648 case 'g': event=TTEV_NULL; break;
649 case 'h': event=TTEV_BACKSP; break;
650 case 'k': event=TTEV_KILL; break;
651 case 'm': event=TTEV_RET; break;
652 case 'n': event=TTEV_F_LINE; break;
653 case 'o': event=TTEV_OVER; break;
654 case 'p': event=TTEV_B_LINE; break;
655 case 'u': event=TTEV_REPEAT; break;
656 case 'w': event=TTEV_WRAP; break;
657 }
658 }
659 else if (key_code & TEXTTOOL_KB_FLAG_SPECIAL)
660 {
661 switch(c)
662 {
663 case 0x48: event = TTEV_B_LINE; break;
664 case 0x50: event = TTEV_F_LINE; break;
665 case 0x4b: event = TTEV_B_CHAR; break;
666 case 0x4d: event = TTEV_F_CHAR; break;
667 }
668 }
669 else
670 {
671 switch(c)
672 {
673 case 0xd: event = TTEV_RET; break;
674 case 0x8: event = TTEV_BACKSP; break;
675 }
676 }
677 // mprintf ("event = %d\n TTEV_RET = %d TTEV_NULL = %d\n",event,TTEV_RET,TTEV_NULL);
678 if (event == TTEV_NULL)
679 {
680 if (isprint(c)) event=c;
681 }
682 ret=_tt_do_event(event);
683 if (ret&TTCHG_CURSOR) LGCursor(_tt->scr_loc.crn.pt.x+_tt->cur_w,_tt->scr_loc.crn.pt.y+_tt->cur_h-_tt->disp_y);
684 if (ret&TTCHG_REDRAW) tt_display_all(_tt,NULL);
685 return (event==TTEV_RET)?_tt->cur_h:-1;
686 }
687
tt_parse_string(TextTool * tt,char * st)688 long tt_parse_string(TextTool *tt, char *st)
689 {
690 char c;
691 int ret, i;
692 int event;
693 _tt_top(tt);
694
695 for (i=0; i<strlen(st); i++)
696 {
697 c = st[i];
698 event = TTEV_NULL;
699 if (c == '\n')
700 { event = TTEV_RET; }
701 else
702 { if (isprint(c)) event=c; }
703 ret=_tt_do_event(event);
704 if (ret&TTCHG_CURSOR) LGCursor(_tt->scr_loc.crn.pt.x+_tt->cur_w,_tt->scr_loc.crn.pt.y+_tt->cur_h-_tt->disp_y);
705 if (ret&TTCHG_REDRAW) tt_display_all(_tt,NULL);
706 }
707 return (event==TTEV_RET)?_tt->cur_h:-1;
708 }
709
tt_get(TextTool * tt,long line_num)710 char *tt_get(TextTool *tt, long line_num)
711 {
712 _tt_top(tt);
713 return (line_num>=_tt->max_h)?NULL:_tt->lines[line_num];
714 }
715
716
717
718
719
720
721 // i received a phone call lying in my bed, the other night
722 // i recognized her voice, she asked me out, i said all right
723 // i pulled up along the curb, she walked in front of my car
724 // she was looking nice, she was looking nice, and i said
725 // it was interesting watching her face as it was pressed against my windshield
726 // it was interesting watching her face as it was pressed against my windshield
727 // against my windshield
728
729 // feel things going through my head, troubling me and making me nervous
730 // feel things going through my head, troubling me and making me nervous
731
732 // - "Windshield", Green Magnet School, _Blood Music_
733