Introduction
Introduction Statistics Contact Development Disclaimer Help
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",…
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 ve…
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…
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 ar…
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…
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…
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)…
632 goto vis_exit;
633 break;
634 case 'f':/* fill */
635 f = get_key(fc, "fill char: "); /** FALL…
636 case 'x':/* erase */
637 if (c == 'x')
638 yank_region(MIN(orig_x,x), MIN(o…
639 copy_lines_to_ring(MIN(orig_y, y), MAX(o…
640 erase_box(orig_x, orig_y, f);
641 erase_blank_lines(MIN(y,orig_y), MAX(y, …
642 copy_lines_to_ring(MIN(orig_y, y), MAX(o…
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_STAT…
649 crop_to_rect(MIN(x, orig_x), MIN(y, orig…
650 copy_lines_to_ring(0, HEIGHT-1, NEW_STAT…
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
You are viewing proxied material from bitreich.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.