diff options
| author | KatolaZ <katolaz@freaknet.org> | 2019-07-18 17:45:38 +0100 | 
|---|---|---|
| committer | KatolaZ <katolaz@freaknet.org> | 2019-07-18 17:45:38 +0100 | 
| commit | 478c03adcdc7d76595a311a0dba682917ab97d62 (patch) | |
| tree | f4680c8d79b4b3bf1d5fe3126896bfaccd464dff | |
initial commit
| -rw-r--r-- | README | 2 | ||||
| -rw-r--r-- | TODO | 9 | ||||
| -rw-r--r-- | gramscii.c | 353 | 
3 files changed, 364 insertions, 0 deletions
| @@ -0,0 +1,2 @@ +Simple tool to draw ascii box plots from the terminal. +No need to use 1 million line of javascript code on a browser. @@ -0,0 +1,9 @@ ++ optimize redraws (i.e., avoid to redraw if possible) +- change cursor shape according to action ++ implement box +- implement arrow +- set different box styles ++ add status bar +- get screen geometry +- allow scrolling (both vertical and horizontal) +  diff --git a/gramscii.c b/gramscii.c new file mode 100644 index 0000000..40d1f1e --- /dev/null +++ b/gramscii.c @@ -0,0 +1,353 @@ +/* +* +* This is `gramscii`, a simple tool to create ascii box graphs +* +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <termios.h> +#include <unistd.h> +#include <signal.h> +#include <string.h> + +#define MOVE   0x00 +#define BOX    0x01 +#define ARROW  0x02 +#define TEXT   0x04 + + +#define DIR_R  0x01 +#define DIR_U  0x02 +#define DIR_D  0x04 +#define DIR_L  0x08 + + +#define WIDTH  100 +#define HEIGHT  25 + +#define BG        ' ' +#define PTR       '+' +#define UND       '_' +#define LINE_H    '-' +#define LINE_V    '|' +#define DBLINE_H  '=' +#define DBLINE_V  'u' +#define BLDLINE   '#' +#define ARR_L     '<' +#define ARR_R     '>' +#define ARR_U     '^' +#define ARR_D     'v' + + +#define MIN(x,y)  (x) < (y) ? (x) : (y) +#define MAX(x,y)  (x) > (y) ? (x) : (y) + +char screen[HEIGHT][WIDTH+1]; + +int state; +int dir; +int x; +int y; +int step; +char cursor; +char corner; +char box_line_h; +char box_line_v; +char arrow_line_h; +char arrow_line_v; + +struct termios t1, t2; + + +void cleanup(int s){ + +	printf("\033[;H\033[2J"); +	tcsetattr(0, TCSANOW, &t1); +	exit(0); +} + +void show_cursor(){ +	printf("\033[%d;%df", y+1, x+1); +	//putchar(screen[y][x]); +	//printf("\033[%d;%df", y+1, x+2); +} + +void set(char c){ +	screen[y][x] = c; +} + +void set_xy(int x, int y, char c){ +	/* FIXME: check if x and y are valid!!!! */ +	screen[y][x] = c; +} + +void draw_xy(int x, int y, char c){ +	/* FIXME: check if x and y are valid!!!! */ +	printf("\033[%d;%df",y+1,x+1); +	putchar(c);	 +} + +void clear(){ +	screen[y][x] = BG; +} + +void init_screen(){ +	int i; +	for(i=0; i<HEIGHT; i++){ +		memset(screen[i], ' ', WIDTH); +		screen[i][WIDTH]='\0'; +	} +	cursor = PTR; +	corner = PTR; +	box_line_h = LINE_H; +	box_line_v = LINE_V; +	arrow_line_h = LINE_H;	 +	arrow_line_v = LINE_V;	 +} + +char* state_str(){ +	switch(state){ +		case MOVE: +			return "mv "; +		case TEXT: +			return "txt"; +		case BOX: +			return "box"; +		case ARROW: +			return "arr"; +	} +} + + +void status_bar(){ +	 +	printf("\033[%d;1f\033[7m", HEIGHT+1); +	printf(" x: %d y: %d -- mode: %s", x, y, state_str()); +	printf("\033[0m"); +} + +int redraw(){ +	int i; +	 +	printf("\033[2J\033[1;1H"); +	for (i=0;i<HEIGHT;i++){ +		fprintf(stdout,"%s\n",screen[i]); +	} +	status_bar(); +	show_cursor(); +	step = 1; +} + +void update_current(){ +	printf("\033[%d'%df",y+1,x+1); +	putchar(screen[y][x]); +} + + +void init(){ + +	signal(SIGHUP, cleanup); +	signal(SIGINT, cleanup); +	signal(SIGTERM, cleanup); +	signal(SIGQUIT, cleanup); +	 +	tcgetattr(0, &t1); +	t2 = t1; +	t2.c_lflag &= ~(ICANON | ECHO); +	tcsetattr(0, TCSANOW, &t2); +	 +	init_screen(); +	x = WIDTH/2; +	y = HEIGHT/2; +	redraw(); +} + +void check_bound(){ +	if (x<0) x=0; +	else if (x>=WIDTH) x = WIDTH-1; +	if (y<0) y=0; +	else if (y>=HEIGHT) y = HEIGHT -1;  +} + + +void get_text(){ +	char c; +	int orig_x = x, orig_y = y; +	 +	//cursor = UND; +	redraw(); +	while((c=getchar())!=EOF && c != 27){ +		if(c=='\n'){ +			set(BG); +			y += 1; +			x = orig_x; +		} +		else { +			set(c); +			update_current(); +			x += 1; +			if (x >= WIDTH) +				x = orig_x; +		} +		check_bound(); +		status_bar(); +		show_cursor(); +	} +	cursor = PTR; +	state=MOVE; +} + + +void fix_box(int x1, int y1){ + +	int xmin, ymin, xmax, ymax; +	int i; +	 +	xmin = MIN(x, x1); +	xmax = MAX(x, x1); +	ymin = MIN(y, y1); +	ymax = MAX(y, y1); + +	 +	for(i=xmin+1; i<=xmax; i++){ +		set_xy(i, ymin, box_line_h); +		set_xy(i, ymax, box_line_h); +	} +	for(i=ymin+1; i<=ymax; i++){ +		set_xy(xmin, i, box_line_v); +		set_xy(xmax, i, box_line_v); +	} +	set_xy(xmin, ymin, corner); +	set_xy(xmin, ymax, corner); +	set_xy(xmax, ymin, corner); +	set_xy(xmax, ymax, corner); +} + +void draw_box(int x1, int y1){ + +	int xmin, ymin, xmax, ymax; +	int i; +	 +	xmin = MIN(x, x1); +	xmax = MAX(x, x1); +	ymin = MIN(y, y1); +	ymax = MAX(y, y1); + +	 +	for(i=xmin+1; i<=xmax; i++){ +		draw_xy(i, ymin, box_line_h); +		draw_xy(i, ymax, box_line_h); +	} +	for(i=ymin+1; i<=ymax; i++){ +		draw_xy(xmin, i, box_line_v); +		draw_xy(xmax, i, box_line_v); +	} +	draw_xy(xmin, ymin, corner); +	draw_xy(xmin, ymax, corner); +	draw_xy(xmax, ymin, corner); +	draw_xy(xmax, ymax, corner); +	show_cursor(); +} + + +void get_box(){ +	char c; +	int orig_x=x, orig_y=y; + +	set(PTR); +	redraw(); +	while((c=getchar())!=EOF && c != 27){ +		switch(c){ +			case 'H': step = 5; +			case 'h':  +				x -= step; +				break;	 +			case 'J': step = 5; +			case 'j': +				y += step; +				break; +			case 'K': step = 5; +			case 'k': +				y -= step; +				break; +			case 'L': step = 5; +			case 'l': +				x += step; +				break; 	 +		} +		check_bound(); +		redraw(); +		draw_box(orig_x, orig_y); +		status_bar(); +		show_cursor(); +	} +	fix_box(orig_x, orig_y); +	redraw(); +} + + +int commands(){ + +	char c; +	while((c=getchar())!=EOF){ +		//screen[y][x]=BG; +		switch(c){ +			case 'H': +				step=5; +			case 'h': +				x-=step; +				break; +			case 'J': +				step=5; +			case 'j': +				y+=step; +				break; +			case 'K': +				step=5; +			case 'k': +				y-=step; +				break; +			case 'L': +				step=5; +			case 'l': +				x+=step; +				break; +			case 'i': +				state = TEXT; +				get_text(); +				break; +			case 'r': +				redraw(); +				break; +			case 'b': +				get_box(); +				break; +			case 'Q': +			case 'q': +				cleanup(0); +				exit(0); +				break; +			default:; +				//statu("got: %d\n", c); +		} +		check_bound(); +		//update(); +		//redraw(); +		status_bar(); +		show_cursor(); +		step = 1; +	} + +} + + + + +int main(int argc, char *argv[]){ + +	init(); + +	commands(); +	cleanup(0); +} | 
