|
|
draw.c - gramscii - A simple editor for ASCII box-and-arrow charts |
|
|
 |
Log |
|
|
 |
Files |
|
|
 |
Refs |
|
|
 |
Tags |
|
|
 |
README |
|
|
 |
LICENSE |
|
|
|
--- |
|
|
|
draw.c (14191B) |
|
|
|
--- |
|
|
|
1 #define _POSIX_C_SOURCE 200112L |
|
|
|
2 |
|
|
|
3 #include <stdlib.h> |
|
|
|
4 #include <string.h> |
|
|
|
5 |
|
|
|
6 #include "gramscii.h" |
|
|
|
7 #include "config.h" |
|
|
|
8 |
|
|
|
9 /** Extern declarations **/ |
|
|
|
10 |
|
|
|
11 extern int WIDTH, HEIGHT; |
|
|
|
12 extern lineset_t screen; /* what is visualised */ |
|
|
|
13 extern lineset_t cutbuf; /* cut/paste buffer */ |
|
|
|
14 extern lineset_t *undo; /* undo list */ |
|
|
|
15 |
|
|
|
16 extern int undo_cur;/* undo position */ |
|
|
|
17 extern int undo_lst;/* last valid undo position */ |
|
|
|
18 |
|
|
|
19 |
|
|
|
20 extern int mode;/* mode */ |
|
|
|
21 extern int dir;/* line direction */ |
|
|
|
22 extern int step;/* current step */ |
|
|
|
23 extern int x; |
|
|
|
24 extern int y; |
|
|
|
25 extern char corner; |
|
|
|
26 extern char modified; /* set to 1 if screen modified since last save */ |
|
|
|
27 |
|
|
|
28 /* line and arrow markers */ |
|
|
|
29 extern int cur_hl, cur_vl, cur_corn, cur_start, cur_end; |
|
|
|
30 extern char line_h; |
|
|
|
31 extern char line_v; |
|
|
|
32 extern char mark_st; |
|
|
|
33 extern char mark_end; |
|
|
|
34 |
|
|
|
35 /* number of available markers for each type */ |
|
|
|
36 extern int hlines_sz; |
|
|
|
37 extern int vlines_sz; |
|
|
|
38 extern int corners_sz; |
|
|
|
39 extern int stmarks_sz; |
|
|
|
40 extern int endmarks_sz; |
|
|
|
41 |
|
|
|
42 |
|
|
|
43 extern char autoend; /* set to 1 in auto-arrow mode */ |
|
|
|
44 |
|
|
|
45 /* Used by draw_arrow to identify the bounding box */ |
|
|
|
46 extern int a_miny; |
|
|
|
47 extern int a_maxy; |
|
|
|
48 |
|
|
|
49 /*** drawing-related functions ***/ |
|
|
|
50 |
|
|
|
51 /*** Lines and markers ***/ |
|
|
|
52 |
|
|
|
53 void toggle_hline(){ |
|
|
|
54 |
|
|
|
55 cur_hl = (cur_hl + 1) % hlines_sz; |
|
|
|
56 line_h = hlines[cur_hl]; |
|
|
|
57 |
|
|
|
58 } |
|
|
|
59 |
|
|
|
60 void toggle_corner(){ |
|
|
|
61 |
|
|
|
62 cur_corn = (cur_corn + 1 ) % corners_sz; |
|
|
|
63 corner = corners[cur_corn]; |
|
|
|
64 |
|
|
|
65 } |
|
|
|
66 |
|
|
|
67 void toggle_vline(){ |
|
|
|
68 |
|
|
|
69 cur_vl = (cur_vl + 1) % vlines_sz; |
|
|
|
70 line_v = vlines[cur_vl]; |
|
|
|
71 |
|
|
|
72 } |
|
|
|
73 |
|
|
|
74 void toggle_st_mark(){ |
|
|
|
75 |
|
|
|
76 cur_start = (cur_start + 1 ) % stmarks_sz; |
|
|
|
77 mark_st = st_marks[cur_start]; |
|
|
|
78 } |
|
|
|
79 |
|
|
|
80 void toggle_end_mark(){ |
|
|
|
81 |
|
|
|
82 cur_end = (cur_end+ 1 ) % endmarks_sz; |
|
|
|
83 mark_end = end_marks[cur_end]; |
|
|
|
84 } |
|
|
|
85 |
|
|
|
86 int change_style(char c){ |
|
|
|
87 switch(c){ |
|
|
|
88 case '-': |
|
|
|
89 toggle_hline(); |
|
|
|
90 break; |
|
|
|
91 case '|': |
|
|
|
92 toggle_vline(); |
|
|
|
93 break; |
|
|
|
94 case '+': |
|
|
|
95 toggle_corner(); |
|
|
|
96 break; |
|
|
|
97 case '<': |
|
|
|
98 toggle_st_mark(); |
|
|
|
99 break; |
|
|
|
100 case '>': |
|
|
|
101 toggle_end_mark(); |
|
|
|
102 break; |
|
|
|
103 case '.': |
|
|
|
104 reset_styles(); |
|
|
|
105 break; |
|
|
|
106 default: |
|
|
|
107 return 0; |
|
|
|
108 } |
|
|
|
109 return c; |
|
|
|
110 } |
|
|
|
111 |
|
|
|
112 |
|
|
|
113 |
|
|
|
114 |
|
|
|
115 /***** text, box, arrows *****/ |
|
|
|
116 |
|
|
|
117 void get_text(FILE *fc){ |
|
|
|
118 char c; |
|
|
|
119 int orig_x = x; |
|
|
|
120 |
|
|
|
121 redraw(); |
|
|
|
122 copy_lines_to_ring(y, y, PRV_STATE); |
|
|
|
123 while((c=fgetc(fc))!=EOF && c != 27){ |
|
|
|
124 if(c=='\n'){ |
|
|
|
125 set_cur(BG); |
|
|
|
126 copy_lines_to_ring(y,y, NEW_STATE); |
|
|
|
127 y += 1; |
|
|
|
128 copy_lines_to_ring(y, y, PRV_STATE); |
|
|
|
129 x = orig_x; |
|
|
|
130 } |
|
|
|
131 else { |
|
|
|
132 set_cur(c); |
|
|
|
133 update_current(); |
|
|
|
134 modified = 1; |
|
|
|
135 x += 1; |
|
|
|
136 if (x >= WIDTH) |
|
|
|
137 x = orig_x; |
|
|
|
138 } |
|
|
|
139 check_bound(&x, &y); |
|
|
|
140 status_bar(); |
|
|
|
141 show_cursor(); |
|
|
|
142 } |
|
|
|
143 if (modified) |
|
|
|
144 copy_lines_to_ring(y, y, NEW_STATE); |
|
|
|
145 mode=MOVE; |
|
|
|
146 } |
|
|
|
147 |
|
|
|
148 void draw_box(int x1, int y1, int fix){ |
|
|
|
149 |
|
|
|
150 int xmin, ymin, xmax, ymax; |
|
|
|
151 int i; |
|
|
|
152 void (*f)(int, int, char); |
|
|
|
153 |
|
|
|
154 |
|
|
|
155 xmin = MIN(x, x1); |
|
|
|
156 xmax = MAX(x, x1); |
|
|
|
157 ymin = MIN(y, y1); |
|
|
|
158 ymax = MAX(y, y1); |
|
|
|
159 |
|
|
|
160 if (fix == FIX){ |
|
|
|
161 f = set_xy; |
|
|
|
162 copy_lines_to_ring(ymin, ymax, PRV_STATE); |
|
|
|
163 } |
|
|
|
164 else |
|
|
|
165 f = draw_xy; |
|
|
|
166 |
|
|
|
167 for(i=xmin+1; i<=xmax; i++){ |
|
|
|
168 f(i, ymin, line_h); |
|
|
|
169 f(i, ymax, line_h); |
|
|
|
170 } |
|
|
|
171 for(i=ymin+1; i<=ymax; i++){ |
|
|
|
172 f(xmin, i, line_v); |
|
|
|
173 f(xmax, i, line_v); |
|
|
|
174 } |
|
|
|
175 f(xmin, ymin, corner); |
|
|
|
176 f(xmin, ymax, corner); |
|
|
|
177 f(xmax, ymin, corner); |
|
|
|
178 f(xmax, ymax, corner); |
|
|
|
179 if (fix == FIX) |
|
|
|
180 copy_lines_to_ring(ymin, ymax, NEW_STATE); |
|
|
|
181 show_cursor(); |
|
|
|
182 } |
|
|
|
183 |
|
|
|
184 void draw_parallelogram(int x1, int y1, char st, char fix){ |
|
|
|
185 int xmin, ymin, xmax, ymax; |
|
|
|
186 int dy, minoff, maxoff, xoff, xincr; |
|
|
|
187 int i; |
|
|
|
188 char lean; |
|
|
|
189 void (*f)(int, int, char); |
|
|
|
190 |
|
|
|
191 |
|
|
|
192 xmin = MIN(x, x1); |
|
|
|
193 xmax = MAX(x, x1); |
|
|
|
194 ymin = MIN(y, y1); |
|
|
|
195 ymax = MAX(y, y1); |
|
|
|
196 dy = ymax - ymin; |
|
|
|
197 |
|
|
|
198 if (fix == FIX){ |
|
|
|
199 f = set_xy; |
|
|
|
200 copy_lines_to_ring(ymin, ymax, PRV_STATE); |
|
|
|
201 } |
|
|
|
202 else |
|
|
|
203 f = draw_xy; |
|
|
|
204 if (st == BOX_PARR){ |
|
|
|
205 minoff = dy; |
|
|
|
206 maxoff = 0; |
|
|
|
207 lean = '/'; |
|
|
|
208 xincr = -1; |
|
|
|
209 } |
|
|
|
210 else { |
|
|
|
211 minoff = 0; |
|
|
|
212 maxoff = dy; |
|
|
|
213 lean = '\\'; |
|
|
|
214 xincr = +1; |
|
|
|
215 } |
|
|
|
216 for(i=xmin+1; i<=xmax-dy; i++){ |
|
|
|
217 f(i+minoff, ymin, line_h); |
|
|
|
218 f(i+maxoff, ymax, line_h); |
|
|
|
219 } |
|
|
|
220 |
|
|
|
221 for(i=ymin+1, xoff=minoff; i<=ymax; i++, xoff += xincr){ |
|
|
|
222 f(xmin+(xoff+xincr), i, lean); |
|
|
|
223 if (minoff) |
|
|
|
224 f(xmax - (minoff - xoff - xincr), i, lean); |
|
|
|
225 else |
|
|
|
226 f(xmax - (maxoff - xoff - xincr), i, lean); |
|
|
|
227 } |
|
|
|
228 f(xmin+minoff, ymin, corner); |
|
|
|
229 f(xmin+maxoff, ymax, corner); |
|
|
|
230 f(xmax-maxoff, ymin, corner); |
|
|
|
231 f(xmax-minoff, ymax, corner); |
|
|
|
232 if (fix == FIX) |
|
|
|
233 copy_lines_to_ring(ymin, ymax, NEW_STATE); |
|
|
|
234 show_cursor(); |
|
|
|
235 |
|
|
|
236 } |
|
|
|
237 |
|
|
|
238 char flip_par_lean(char st){ |
|
|
|
239 if (st == BOX_PARR) |
|
|
|
240 return BOX_PARL; |
|
|
|
241 else if (st == BOX_PARL) |
|
|
|
242 return BOX_PARR; |
|
|
|
243 return st; |
|
|
|
244 } |
|
|
|
245 |
|
|
|
246 void draw_trapezium(int x1, int y1, char st, char fix){ |
|
|
|
247 int xmin, ymin, xmax, ymax; |
|
|
|
248 int dx, dy, ylong, yshort, xoff; |
|
|
|
249 int xincr; |
|
|
|
250 int i; |
|
|
|
251 void (*f)(int, int, char); |
|
|
|
252 char left_c, right_c; |
|
|
|
253 |
|
|
|
254 xmin = MIN(x, x1); |
|
|
|
255 xmax = MAX(x, x1); |
|
|
|
256 ymin = MIN(y, y1); |
|
|
|
257 ymax = MAX(y, y1); |
|
|
|
258 dx = (xmax - xmin); |
|
|
|
259 dy = ymax - ymin; |
|
|
|
260 /* dy = MAX(dx2, dy); */ |
|
|
|
261 #ifdef DEBUG |
|
|
|
262 fprintf(stderr, "dy: %d dx: %d\n", dy, dx); |
|
|
|
263 #endif |
|
|
|
264 if (fix == FIX){ |
|
|
|
265 f = set_xy; |
|
|
|
266 copy_lines_to_ring(ymin, ymax, PRV_STATE); |
|
|
|
267 } |
|
|
|
268 else |
|
|
|
269 f = draw_xy; |
|
|
|
270 |
|
|
|
271 /* This is valid only for "upper" trapezoids */ |
|
|
|
272 if (STYLE_IS(st, BOX_TRAP_U)){ |
|
|
|
273 #ifdef DEBUG |
|
|
|
274 fprintf(stderr, "This is an 'upward' trapezium\n"); |
|
|
|
275 #endif |
|
|
|
276 ylong = ymax; |
|
|
|
277 yshort = ymin; |
|
|
|
278 xoff = dy; |
|
|
|
279 xincr = -1; |
|
|
|
280 left_c = '/'; |
|
|
|
281 right_c = '\\'; |
|
|
|
282 } |
|
|
|
283 else if (STYLE_IS(st, BOX_TRAP_D)){ |
|
|
|
284 #ifdef DEBUG |
|
|
|
285 fprintf(stderr, "This is a 'downward' trapezium\n"); |
|
|
|
286 #endif |
|
|
|
287 ylong = ymin; |
|
|
|
288 yshort = ymax; |
|
|
|
289 xoff = dy; |
|
|
|
290 xincr = +1; |
|
|
|
291 right_c = '/'; |
|
|
|
292 left_c = '\\'; |
|
|
|
293 } |
|
|
|
294 /* Long side */ |
|
|
|
295 for(i=xmin+1; i<=xmax; i++){ |
|
|
|
296 f(i, ylong, line_h); |
|
|
|
297 } |
|
|
|
298 |
|
|
|
299 if (STYLE_IS(st, BOX_TRAP_L)){ |
|
|
|
300 /* short side */ |
|
|
|
301 left_c = '/'; |
|
|
|
302 right_c = line_v; |
|
|
|
303 for(i=xmin+xoff;i<xmax; i++){ |
|
|
|
304 f(i, yshort, line_h); |
|
|
|
305 } |
|
|
|
306 xoff = dy; |
|
|
|
307 if (STYLE_IS(st, BOX_TRAP_D)){ |
|
|
|
308 xoff = 0; |
|
|
|
309 left_c = '\\'; |
|
|
|
310 } |
|
|
|
311 for(i=ymin; i<ymax; i++, xoff += xincr){ |
|
|
|
312 f(xmin+xoff, i, left_c); |
|
|
|
313 f(xmax, i, right_c); |
|
|
|
314 } |
|
|
|
315 f(xmin+dy, yshort, corner); |
|
|
|
316 f(xmax, yshort, corner); |
|
|
|
317 } |
|
|
|
318 else if (STYLE_IS(st, BOX_TRAP_R)){ |
|
|
|
319 right_c = '\\'; |
|
|
|
320 left_c = line_v; |
|
|
|
321 for(i=xmin; i<xmax-xoff; i++){ |
|
|
|
322 f(i, yshort, line_h); |
|
|
|
323 } |
|
|
|
324 xoff = dy-1; |
|
|
|
325 if (STYLE_IS(st, BOX_TRAP_D)){ |
|
|
|
326 xoff = 1; |
|
|
|
327 right_c = '/'; |
|
|
|
328 } |
|
|
|
329 for(i=ymin+1; i<ymax; i++, xoff += xincr){ |
|
|
|
330 f(xmin, i, left_c); |
|
|
|
331 f(xmax-xoff, i, right_c); |
|
|
|
332 } |
|
|
|
333 f(xmin, yshort, corner); |
|
|
|
334 f(xmax-dy, yshort, corner); |
|
|
|
335 } |
|
|
|
336 else if (STYLE_IS(st, BOX_TRAP_C)){ |
|
|
|
337 xoff = dy; |
|
|
|
338 for (i=xmin+xoff; i<=xmax-xoff; i++){ |
|
|
|
339 f(i, yshort, line_h); |
|
|
|
340 } |
|
|
|
341 xoff = dy - 1; |
|
|
|
342 if (STYLE_IS(st, BOX_TRAP_D)) |
|
|
|
343 xoff = 1; |
|
|
|
344 for(i=ymin+1; i<ymax; i++, xoff += xincr){ |
|
|
|
345 f(xmin + xoff, i, left_c); |
|
|
|
346 f(xmax - xoff, i, right_c); |
|
|
|
347 } |
|
|
|
348 f(xmin+dy, yshort, corner); |
|
|
|
349 f(xmax-dy, yshort, corner); |
|
|
|
350 } |
|
|
|
351 |
|
|
|
352 |
|
|
|
353 f(xmin, ylong, corner); |
|
|
|
354 f(xmax, ylong, corner); |
|
|
|
355 |
|
|
|
356 |
|
|
|
357 if (fix == FIX) |
|
|
|
358 copy_lines_to_ring(ymin, ymax, NEW_STATE); |
|
|
|
359 show_cursor(); |
|
|
|
360 |
|
|
|
361 } |
|
|
|
362 |
|
|
|
363 /* |
|
|
|
364 * draw the current box, being it an actual box, a parallelogram, or a |
|
|
|
365 * trapezium |
|
|
|
366 */ |
|
|
|
367 void update_box(int x1, int y1, char st, char fix){ |
|
|
|
368 |
|
|
|
369 if (st == BOX_RECT) |
|
|
|
370 draw_box(x1, y1, fix); |
|
|
|
371 else if (st & BOX_PAR) |
|
|
|
372 draw_parallelogram(x1, y1, st, fix); |
|
|
|
373 else if (st & BOX_TRAP) |
|
|
|
374 draw_trapezium(x1, y1, st, fix); |
|
|
|
375 status_bar(); |
|
|
|
376 show_cursor(); |
|
|
|
377 } |
|
|
|
378 |
|
|
|
379 char toggle_trap_type(char st){ |
|
|
|
380 if (st & BOX_TRAP){ |
|
|
|
381 if (st != BOX_TRAP_DR) |
|
|
|
382 st += 1; |
|
|
|
383 else |
|
|
|
384 st = BOX_TRAP_UR; |
|
|
|
385 } |
|
|
|
386 if (st == BOX_TRAP_D) |
|
|
|
387 st += 1; |
|
|
|
388 return st; |
|
|
|
389 } |
|
|
|
390 |
|
|
|
391 int box_end(char c, char st){ |
|
|
|
392 if (c == '\n' || |
|
|
|
393 c == 27 || |
|
|
|
394 ((st == BOX_RECT) && c == 'b') || |
|
|
|
395 ((st & BOX_PAR) && c == 'z') || |
|
|
|
396 ((st & BOX_TRAP) && c == 't')) |
|
|
|
397 return 1; |
|
|
|
398 return 0; |
|
|
|
399 } |
|
|
|
400 |
|
|
|
401 /* draw boxes, parallelograms, and trapezia */ |
|
|
|
402 void get_box(FILE *fc, char st){ |
|
|
|
403 char c; |
|
|
|
404 int orig_x=x, orig_y=y; |
|
|
|
405 redraw(); |
|
|
|
406 step = 1; |
|
|
|
407 #ifdef DEBUG |
|
|
|
408 fprintf(stderr, "box style: %d\n", st); |
|
|
|
409 #endif |
|
|
|
410 draw_box(x,y,NOFIX); |
|
|
|
411 while((c=fgetc(fc))!=EOF && !box_end(c, st)){ |
|
|
|
412 if (c == 'Z' && (st & BOX_PAR)){ |
|
|
|
413 st = flip_par_lean(st); |
|
|
|
414 redraw(); |
|
|
|
415 #ifdef DEBUG |
|
|
|
416 fprintf(stderr, "new parallelogram style: %d\n", st); |
|
|
|
417 #endif |
|
|
|
418 update_box(orig_x, orig_y, st, NOFIX); |
|
|
|
419 continue; |
|
|
|
420 } |
|
|
|
421 else if (c == 'T' && (st & BOX_TRAP)){ |
|
|
|
422 st = toggle_trap_type(st); |
|
|
|
423 #ifdef DEBUG |
|
|
|
424 fprintf(stderr, "new trapezium style: %d\n", st); |
|
|
|
425 #endif |
|
|
|
426 redraw(); |
|
|
|
427 update_box(orig_x, orig_y, st, NOFIX); |
|
|
|
428 continue; |
|
|
|
429 } |
|
|
|
430 if (change_style(c)){ |
|
|
|
431 update_box(orig_x, orig_y, st, NOFIX); |
|
|
|
432 continue; |
|
|
|
433 } |
|
|
|
434 if (!move_around(c, fc, 1)) |
|
|
|
435 continue; |
|
|
|
436 check_bound(&x, &y); |
|
|
|
437 redraw(); |
|
|
|
438 step = 1; |
|
|
|
439 update_box(orig_x, orig_y, st, NOFIX); |
|
|
|
440 } |
|
|
|
441 if (((st == BOX_RECT ) && (c == 'b' || c == '\n')) || |
|
|
|
442 ( (st & BOX_PAR ) && (c == 'z' || c == '\n')) || |
|
|
|
443 ( (st & BOX_TRAP ) && (c == 't' || c == '\n'))){ |
|
|
|
444 update_box(orig_x, orig_y, st, FIX); |
|
|
|
445 modified = 1; |
|
|
|
446 } |
|
|
|
447 redraw(); |
|
|
|
448 mode = MOVE; |
|
|
|
449 } |
|
|
|
450 |
|
|
|
451 void draw_arrow(int xl, int yl, short *a, int a_len, int fix){ |
|
|
|
452 |
|
|
|
453 int i, j, cur_dir; |
|
|
|
454 char line; |
|
|
|
455 void (*f)(int, int, char); |
|
|
|
456 |
|
|
|
457 a_miny = a_maxy = yl; |
|
|
|
458 if (fix == FIX) |
|
|
|
459 f = set_xy; |
|
|
|
460 else |
|
|
|
461 f = draw_xy; |
|
|
|
462 |
|
|
|
463 f(xl, yl, mark_st); |
|
|
|
464 if (!a_len){ |
|
|
|
465 show_cursor(); |
|
|
|
466 return; |
|
|
|
467 } |
|
|
|
468 cur_dir=DIR_N; |
|
|
|
469 for (i=0; i<a_len; i+=2){ |
|
|
|
470 if (i>0) { |
|
|
|
471 /* If we are switching between horizontal and vertical, put a "corner" */ |
|
|
|
472 if (((cur_dir & DIR_HOR) && (a[i] & DIR_VER)) || |
|
|
|
473 ((cur_dir & DIR_VER) && (a[i] & DIR_HOR))){ |
|
|
|
474 f(xl, yl, corner); |
|
|
|
475 show_cursor(); |
|
|
|
476 } |
|
|
|
477 } |
|
|
|
478 for(j=0; j<a[i+1]; j++){ |
|
|
|
479 line = (a[i] & DIR_L) || (a[i] & DIR_R) ? line_h : line_v; |
|
|
|
480 xl += progr_x(a[i]); |
|
|
|
481 yl += progr_y(a[i]); |
|
|
|
482 check_bound(&xl, &yl); |
|
|
|
483 if (yl < a_miny) a_miny = yl; |
|
|
|
484 if (yl > a_maxy) a_maxy = yl; |
|
|
|
485 f(xl, yl, line); |
|
|
|
486 } |
|
|
|
487 /* f(x,y,mark_end);*/ |
|
|
|
488 cur_dir = a[i]; |
|
|
|
489 } |
|
|
|
490 if (autoend){ |
|
|
|
491 if (cur_dir != DIR_N) |
|
|
|
492 f(xl,yl, get_mark(cur_dir)); |
|
|
|
493 } |
|
|
|
494 else |
|
|
|
495 f(xl,yl,mark_end); |
|
|
|
496 show_cursor(); |
|
|
|
497 } |
|
|
|
498 |
|
|
|
499 void get_arrow(FILE *fc){ |
|
|
|
500 |
|
|
|
501 char c; |
|
|
|
502 int orig_x=x, orig_y=y, arrow_len; |
|
|
|
503 static short *arrow = NULL; |
|
|
|
504 short *tmp = NULL; |
|
|
|
505 static int arrow_sz; |
|
|
|
506 |
|
|
|
507 if (!arrow){ |
|
|
|
508 arrow_sz = 100; |
|
|
|
509 arrow = malloc(arrow_sz * sizeof(short)); |
|
|
|
510 if (arrow == NULL){ |
|
|
|
511 fprintf(stderr, "Unable to allocate arrow"); |
|
|
|
512 cleanup(1); |
|
|
|
513 } |
|
|
|
514 } |
|
|
|
515 arrow_len = 0; |
|
|
|
516 dir = DIR_N; |
|
|
|
517 |
|
|
|
518 redraw(); |
|
|
|
519 step = 1; |
|
|
|
520 draw_arrow(x,y, arrow, 0, NOFIX); |
|
|
|
521 while((c=fgetc(fc))!=EOF && c != 27 && c!= 'a' && c != '\n'){ |
|
|
|
522 if (change_style(c)) |
|
|
|
523 goto update_arrow; |
|
|
|
524 if (!move_around(c, fc, 0)) |
|
|
|
525 continue; |
|
|
|
526 check_bound(&x, &y); |
|
|
|
527 /* FIXME: if we are out of bound, do nothing? */ |
|
|
|
528 if (arrow_len == arrow_sz){ |
|
|
|
529 arrow_sz *=2; |
|
|
|
530 tmp = realloc(arrow, arrow_sz * sizeof(short)); |
|
|
|
531 if (tmp == NULL){ |
|
|
|
532 fprintf(stderr, "Unable to reallocate arrow"); |
|
|
|
533 cleanup(1); |
|
|
|
534 } |
|
|
|
535 arrow = tmp; |
|
|
|
536 } |
|
|
|
537 if (dir != DIR_N){ |
|
|
|
538 arrow[arrow_len++] = dir; |
|
|
|
539 arrow[arrow_len++] = step; |
|
|
|
540 } |
|
|
|
541 redraw(); |
|
|
|
542 step = 1; |
|
|
|
543 update_arrow: |
|
|
|
544 draw_arrow(orig_x, orig_y, arrow, arrow_len, NOFIX); |
|
|
|
545 status_bar(); |
|
|
|
546 show_cursor(); |
|
|
|
547 } |
|
|
|
548 if (c == 'a' || c == '\n'){ |
|
|
|
549 copy_lines_to_ring(a_miny, a_maxy, PRV_STATE); |
|
|
|
550 draw_arrow(orig_x, orig_y, arrow, arrow_len, FIX); |
|
|
|
551 copy_lines_to_ring(a_miny, a_maxy, NEW_STATE); |
|
|
|
552 modified = 1; |
|
|
|
553 } |
|
|
|
554 redraw(); |
|
|
|
555 mode = MOVE; |
|
|
|
556 } |
|
|
|
557 |
|
|
|
558 |
|
|
|
559 void do_erase(int x1, int y1){ |
|
|
|
560 int i; |
|
|
|
561 switch(dir){ |
|
|
|
562 case DIR_R: |
|
|
|
563 for(i=x1; i<=x; i++) set_xy(i,y,BG); |
|
|
|
564 break; |
|
|
|
565 case DIR_L: |
|
|
|
566 for(i=x1; i>=x; i--) set_xy(i,y,BG); |
|
|
|
567 break; |
|
|
|
568 case DIR_U: |
|
|
|
569 for(i=y1; i>=y; i--) set_xy(x,i,BG); |
|
|
|
570 break; |
|
|
|
571 case DIR_D: |
|
|
|
572 for(i=y1; i<=y; i++) set_xy(x,i,BG); |
|
|
|
573 break; |
|
|
|
574 } |
|
|
|
575 } |
|
|
|
576 |
|
|
|
577 |
|
|
|
578 void erase(FILE *fc){ |
|
|
|
579 /*FIXME: add affected lines to undo */ |
|
|
|
580 char c; |
|
|
|
581 int orig_x = x, orig_y = y; |
|
|
|
582 char first = 1, opened = 0; |
|
|
|
583 status_bar(); |
|
|
|
584 show_cursor(); |
|
|
|
585 while((c=fgetc(fc))!=EOF && c!=27 && c!= 'x' && c != '\n'){ |
|
|
|
586 if (!move_around(c, fc, 0)) continue; |
|
|
|
587 check_bound(&x, &y); |
|
|
|
588 if (first || |
|
|
|
589 (y != orig_y && ! opened) || |
|
|
|
590 (y == orig_y && x != orig_x && !opened) ){ |
|
|
|
591 copy_lines_to_ring(MIN(y, orig_y), MAX(y, orig_y), PRV_STATE); |
|
|
|
592 first = 0; |
|
|
|
593 opened = 1; |
|
|
|
594 } |
|
|
|
595 do_erase(orig_x, orig_y); |
|
|
|
596 if (y != orig_y && opened){ |
|
|
|
597 copy_lines_to_ring(MIN(y, orig_y), MAX(y, orig_y), NEW_STATE); |
|
|
|
598 opened = 0; |
|
|
|
599 } |
|
|
|
600 step = 1; |
|
|
|
601 modified = 1; |
|
|
|
602 orig_x = x; |
|
|
|
603 orig_y = y; |
|
|
|
604 redraw(); |
|
|
|
605 status_bar(); |
|
|
|
606 show_cursor(); |
|
|
|
607 } |
|
|
|
608 if (opened) |
|
|
|
609 copy_lines_to_ring(y, y, NEW_STATE); |
|
|
|
610 mode = MOVE; |
|
|
|
611 } |
|
|
|
612 |
|
|
|
613 |
|
|
|
614 |
|
|
|
615 |
|
|
|
616 |
|
|
|
617 /*** Visual ***/ |
|
|
|
618 |
|
|
|
619 |
|
|
|
620 void visual_box(FILE *fc){ |
|
|
|
621 int orig_x =x, orig_y = y; |
|
|
|
622 char c, f = BG; |
|
|
|
623 |
|
|
|
624 redraw(); |
|
|
|
625 step = 1; |
|
|
|
626 set_video(VIDEO_REV); |
|
|
|
627 draw_box(x,y,NOFIX); |
|
|
|
628 while((c=fgetc(fc))!=EOF && c != 27 && c!= 'v' && c != '\n'){ |
|
|
|
629 if (!move_around(c, fc, 1)) switch(c){ |
|
|
|
630 case 'y': /* yank (copy) */ |
|
|
|
631 yank_region(MIN(orig_x,x), MIN(orig_y,y), MAX(orig_x, x), MAX(orig_y, y)); |
|
|
|
632 goto vis_exit; |
|
|
|
633 break; |
|
|
|
634 case 'f':/* fill */ |
|
|
|
635 f = get_key(fc, "fill char: "); /** FALLTHROUGH **/ |
|
|
|
636 case 'x':/* erase */ |
|
|
|
637 if (c == 'x') |
|
|
|
638 yank_region(MIN(orig_x,x), MIN(orig_y,y), MAX(orig_x, x), MAX(orig_y, y)); |
|
|
|
639 copy_lines_to_ring(MIN(orig_y, y), MAX(orig_y, y), PRV_STATE); |
|
|
|
640 erase_box(orig_x, orig_y, f); |
|
|
|
641 erase_blank_lines(MIN(y,orig_y), MAX(y, orig_y)); |
|
|
|
642 copy_lines_to_ring(MIN(orig_y, y), MAX(orig_y, y), NEW_STATE); |
|
|
|
643 |
|
|
|
644 modified = 1; |
|
|
|
645 goto vis_exit; |
|
|
|
646 break; |
|
|
|
647 case 'C':/* crop-to-region */ |
|
|
|
648 copy_lines_to_ring(0, HEIGHT-1, PRV_STATE); |
|
|
|
649 crop_to_rect(MIN(x, orig_x), MIN(y, orig_y), MAX(x, orig_x), MAX(y, orig_y)); |
|
|
|
650 copy_lines_to_ring(0, HEIGHT-1, NEW_STATE); |
|
|
|
651 modified = 1; |
|
|
|
652 goto vis_exit; |
|
|
|
653 break; |
|
|
|
654 } |
|
|
|
655 check_bound(&x, &y); |
|
|
|
656 set_video(VIDEO_NRM); |
|
|
|
657 redraw(); |
|
|
|
658 step = 1; |
|
|
|
659 f = BG; |
|
|
|
660 set_video(VIDEO_REV); |
|
|
|
661 draw_box(orig_x, orig_y, NOFIX); |
|
|
|
662 status_bar(); |
|
|
|
663 show_cursor(); |
|
|
|
664 } |
|
|
|
665 vis_exit: |
|
|
|
666 set_video(VIDEO_NRM); |
|
|
|
667 redraw(); |
|
|
|
668 mode = MOVE; |
|
|
|
669 } |
|
|
|
670 |
|
|
|
671 /*** yank/paste/undo ***/ |
|
|
|
672 |
|
|
|
673 void paste(){ |
|
|
|
674 int y2; |
|
|
|
675 |
|
|
|
676 y2 = y + cutbuf.num - 1; |
|
|
|
677 copy_lines_to_ring(y, y2, PRV_STATE); |
|
|
|
678 paste_region(x, y); |
|
|
|
679 copy_lines_to_ring(y, y2, NEW_STATE); |
|
|
|
680 redraw(); |
|
|
|
681 } |
|
|
|
682 |
|
|
|
683 void put_lines(lineset_t *u){ |
|
|
|
684 int i, n; |
|
|
|
685 |
|
|
|
686 for (i=0; i< u->num; i++){ |
|
|
|
687 n = u->l[i].n; |
|
|
|
688 ensure_line_length(&(screen.l[i]), strlen(u->l[i].s)); |
|
|
|
689 strcpy(screen.l[n].s, u->l[i].s); |
|
|
|
690 screen.l[n].lst = strlen(u->l[i].s)-1; |
|
|
|
691 } |
|
|
|
692 } |
|
|
|
693 |
|
|
|
694 |
|
|
|
695 void undo_change(){ |
|
|
|
696 if (undo_cur >= 0){ |
|
|
|
697 if (undo_cur > undo_lst) |
|
|
|
698 undo_cur = undo_lst; |
|
|
|
699 put_lines(& (undo[undo_cur])); |
|
|
|
700 undo_cur -= 2; |
|
|
|
701 modified = 1; |
|
|
|
702 } |
|
|
|
703 redraw(); |
|
|
|
704 } |
|
|
|
705 |
|
|
|
706 void redo_change(){ |
|
|
|
707 if (undo_cur <= undo_lst-2){ |
|
|
|
708 if (undo_cur > 0) |
|
|
|
709 put_lines(& (undo[undo_cur+1])); |
|
|
|
710 undo_cur +=2; |
|
|
|
711 put_lines(& (undo[undo_cur+1])); |
|
|
|
712 modified = 1; |
|
|
|
713 } |
|
|
|
714 redraw(); |
|
|
|
715 } |
|
|
|
716 |
|
|
|
717 |
|
|
|
718 /** Comments **/ |
|
|
|
719 |
|
|
|
720 void get_comment(FILE *fc){ |
|
|
|
721 char c; |
|
|
|
722 redraw(); |
|
|
|
723 while((c = fgetc(fc)) != EOF && c != '\n'); |
|
|
|
724 mode = MOVE; |
|
|
|
725 } |
|
|
|
726 |
|