summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKatolaZ <katolaz@freaknet.org>2019-07-18 17:45:38 +0100
committerKatolaZ <katolaz@freaknet.org>2019-07-18 17:45:38 +0100
commit478c03adcdc7d76595a311a0dba682917ab97d62 (patch)
treef4680c8d79b4b3bf1d5fe3126896bfaccd464dff
initial commit
-rw-r--r--README2
-rw-r--r--TODO9
-rw-r--r--gramscii.c353
3 files changed, 364 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..ae699d4
--- /dev/null
+++ b/README
@@ -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.
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..956af84
--- /dev/null
+++ b/TODO
@@ -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);
+}