57b88df4fa164de4f771623c868b0e3d4308ac4b
[smdp.git] / viewer.c
1 #include <ncurses.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4
5 #include "include/parser.h"
6 #include "include/viewer.h"
7
8 static short white_ramp[24] = { 16, 232, 233, 234, 235, 236,
9                                237, 238, 239, 240, 241, 242,
10                                244, 245, 246, 247, 248, 249,
11                                250, 251, 252, 253, 254, 255 };
12
13 static short blue_ramp[24]  = { 16,  17,  17,  18,  18,  19,
14                                 19,  20,  20,  21,  27,  32,
15                                 33,  38,  39,  44,  45,  45,
16                                 81,  81,  51,  51, 123, 123 };
17
18 static short red_ramp[24]   = { 16,  52,  52,  53,  53,  89,
19                                 89,  90,  90, 126, 127, 127,
20                                163, 163, 164, 164, 200, 200,
21                                201, 201, 207, 207, 213, 213 };
22
23 int ncurses_display(deck_t *deck, int notrans, int nofade) {
24
25     int c = 0;          // char
26     int colors = 0;     // amount of colors supported
27     int fade = 0;       // disable color fading by default
28     int trans = -1;     // enable transparency if term supports it
29     int max_lines = 0;  // max lines per slide
30     int max_cols = 0;   // max columns per line
31     int offset;         // text offset
32
33     // header line 1 is displayed at the top
34     int bar_top = (deck->headers > 0) ? 1 : 0;
35     // header line 2 and 3 are displayed at the bottom
36     int bar_bottom = (deck->headers > 1) ? 1 : 0;
37
38     slide_t *slide = deck->slide;
39     line_t *line;
40
41     while(slide) {
42         // set max_lines if line count exceeded
43         max_lines = (slide->lines > max_lines) ? slide->lines : max_lines;
44         line = slide->line;
45         while(line) {
46             // set max_cols if length exceeded
47             max_cols = (line->length > max_cols) ? line->length : max_cols;
48             line = line->next;
49         }
50         slide = slide->next;
51     }
52
53     // replace stdin with current tty if markdown input was piped
54     freopen("/dev/tty", "rw", stdin);
55
56     // init ncurses
57     initscr();
58
59     if((max_cols > COLS) ||
60        (max_lines + bar_top + bar_bottom + 2 > LINES)) {
61
62         fprintf(stderr, "Error: Terminal size %ix%i to small. Need at least %ix%i.\n",
63             COLS, LINES, max_cols, max_lines + bar_top + bar_bottom + 2);
64         endwin();
65         return(1);
66     }
67
68     // replace stdin with current tty if markdown input was piped
69     freopen("/dev/tty", "rw", stdin);
70
71     // disable cursor
72     curs_set(0);
73
74     // disable output of keyboard typing
75     noecho();
76
77     // make getch() process one char at a time
78     cbreak();
79
80     // enable arrow keys
81     keypad(stdscr,TRUE);
82
83     // set colors
84     if(has_colors() == TRUE) {
85         start_color();
86         use_default_colors();
87
88         if(notrans) trans = 0; // 0 is black
89
90         if(COLORS == 256) {
91             // 256 color mode
92             init_pair(CP_WHITE, 255, trans);
93             init_pair(CP_BLUE, 123, trans);
94             init_pair(CP_RED, 213, trans);
95             init_pair(CP_YELLOW, 208, trans);
96
97             // enable color fading
98             if(!nofade) fade = 1;
99         } else {
100
101             // 8 color mode
102             init_pair(CP_WHITE, 7, trans);
103             init_pair(CP_BLUE, 4, trans);
104             init_pair(CP_RED, 1, trans);
105             init_pair(CP_YELLOW, 3, trans);
106         }
107
108         colors = 1;
109     }
110
111     // set background color of main window
112     if(colors)
113         wbkgd(stdscr, COLOR_PAIR(CP_YELLOW));
114
115     // setup header
116     if(bar_top) {
117         line = deck->header;
118         offset = next_blank(line->text, 0) + 1;
119         // add text to header
120         mvwprintw(stdscr,
121                   0, (COLS - line->length + offset) / 2,
122                   "%s", &line->text->text[offset]);
123     }
124
125     // setup footer
126     if(bar_bottom) {
127         line = deck->header->next;
128         offset = next_blank(line->text, 0) + 1;
129         // add text to left footer
130         mvwprintw(stdscr,
131                   LINES - 1, 0,
132                   "%s", &line->text->text[offset]);
133
134         if(deck->headers > 2) {
135             line = deck->header->next->next;
136             offset = next_blank(line->text, 0) + 1;
137             // add text to right footer
138             mvwprintw(stdscr,
139                       LINES - 1, COLS - line->length + offset,
140                       "%s", &line->text->text[offset]);
141         }
142     }
143
144     // make header + fooder visible
145     wrefresh(stdscr);
146
147     // setup main window
148     WINDOW *content = newwin(LINES - bar_top - bar_bottom, COLS, 0 + bar_top, 0);
149     if(colors)
150         wbkgd(content, COLOR_PAIR(CP_WHITE));
151
152     slide = deck->slide;
153     while(slide) {
154         // clear main window
155         werase(content);
156
157         //TODO print lines
158         wprintw(content, "%s", "content");
159
160         // make content visible
161         wrefresh(content);
162
163         // fade in
164         if(fade)
165             fade_in(content, trans, colors);
166
167         // wait for user input
168         c = getch();
169
170         // evaluate user input
171         switch(c) {
172
173             // show previous slide
174             case KEY_UP:
175             case KEY_LEFT:
176             case KEY_BACKSPACE:
177             case 'h':
178             case 'k':
179                 if(slide->prev)
180                     slide = slide->prev;
181                 break;
182
183             // show next slide
184             case KEY_DOWN:
185             case KEY_RIGHT:
186             case KEY_ENTER:
187             case 'j':
188             case 'l':
189                 if(slide->next)
190                     slide = slide->next;
191                 break;
192
193             // quit
194             case 'q':
195                 // do not fade out on exit
196                 fade = 0;
197                 slide = (void*)0;
198                 break;
199         }
200
201         // fade out
202         if(fade)
203             fade_out(content, trans, colors);
204     }
205
206     endwin();
207
208     return(0);
209 }
210
211 void fade_out(WINDOW *window, int trans, int colors) {
212     int i; // increment
213     if(colors) {
214         for(i = 22; i >= 0; i--) {
215             // darken color pairs
216             init_pair(CP_WHITE, white_ramp[i], trans);
217             init_pair(CP_BLUE, blue_ramp[i], trans);
218             init_pair(CP_RED, red_ramp[i], trans);
219             // refresh window with new color
220             wrefresh(window);
221             // delay for our eyes to recognize the change
222             usleep(FADE_DELAY);
223         }
224     }
225 }
226
227 void fade_in(WINDOW *window, int trans, int colors) {
228     int i; // increment
229     if(colors) {
230         for(i = 0; i <= 23; i++) {
231             // lighten color pairs
232             init_pair(CP_WHITE, white_ramp[i], trans);
233             init_pair(CP_BLUE, blue_ramp[i], trans);
234             init_pair(CP_RED, red_ramp[i], trans);
235             // refresh window with new color
236             wrefresh(window);
237             // delay for our eyes to recognize the change
238             usleep(FADE_DELAY);
239         }
240     }
241 }
242