fixed window refresh behavior for #100
[smdp.git] / src / viewer.c
index 8d97139..925efb1 100644 (file)
@@ -2,7 +2,7 @@
  * Functions necessary to display a deck of slides in different color modes
  * using ncurses. Only white, red, and blue are supported, as they can be
  * faded in 256 color mode.
- * Copyright (C) 2014 Michael Goehler
+ * Copyright (C) 2016 Michael Goehler
  *
  * This file is part of mdp.
  *
@@ -60,7 +60,7 @@ static short red_ramp_invert[24]   = { 15, 231, 231, 224, 224, 225,
                                       206, 207, 201, 200, 199, 199,
                                       198, 198, 197, 197, 196, 196};
 
-int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reload, int noreload) {
+int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reload, int noreload, int slidenum) {
 
     int c = 0;          // char
     int i = 0;          // iterate
@@ -73,12 +73,13 @@ int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reloa
     int max_lines = 0;  // max lines per slide
     int max_cols = 0;   // max columns per line
     int offset;         // text offset
+    int stop = 0;       // passed stop bits per slide
 
     // header line 1 is displayed at the top
     int bar_top = (deck->headers > 0) ? 1 : 0;
     // header line 2 is displayed at the bottom
     // anyway we display the slide number at the bottom
-    int bar_bottom = 1;
+    int bar_bottom = (slidenum || deck->headers > 1)? 1 : 0;
 
     slide_t *slide = deck->slide;
     line_t *line;
@@ -92,11 +93,10 @@ int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reloa
 
         while(line && line->text) {
 
-            if (line->text->text)
-                lc += url_count_inline(line->text->text);
-
-            if (line->text->text)
-                line->length -= url_len_inline(line->text->text);
+            if (line->text->value) {
+                lc += url_count_inline(line->text->value);
+                line->length -= url_len_inline(line->text->value);
+            }
 
             if(line->length > COLS) {
                 i = line->length;
@@ -229,12 +229,14 @@ int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reloa
         colors = 1;
     }
 
-    // set background color of main window
+    // set background color for main window
     if(colors)
-        wbkgd(stdscr, COLOR_PAIR(CP_YELLOW));
+        wbkgd(stdscr, COLOR_PAIR(CP_WHITE));
 
-    // setup main window
+    // setup content window
     WINDOW *content = newwin(LINES - bar_top - bar_bottom, COLS, 0 + bar_top, 0);
+
+    // set background color of content window
     if(colors)
         wbkgd(content, COLOR_PAIR(CP_WHITE));
 
@@ -261,6 +263,10 @@ int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reloa
         // always resize window in case terminal geometry has changed
         wresize(content, LINES - bar_top - bar_bottom, COLS);
 
+        // set main window text color
+        if(colors)
+            wattron(stdscr, COLOR_PAIR(CP_YELLOW));
+
         // setup header
         if(bar_top) {
             line = deck->header;
@@ -268,48 +274,81 @@ int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reloa
             // add text to header
             mvwaddwstr(stdscr,
                        0, (COLS - line->length + offset) / 2,
-                       &line->text->text[offset]);
+                       &line->text->value[offset]);
         }
 
         // setup footer
         if(deck->headers > 1) {
             line = deck->header->next;
             offset = next_blank(line->text, 0) + 1;
-            // add text to left footer
-            mvwaddwstr(stdscr,
-                       LINES - 1, 3,
-                       &line->text->text[offset]);
+            switch(slidenum) {
+                case 0: // add text to center footer
+                    mvwaddwstr(stdscr,
+                               LINES - 1, (COLS - line->length + offset) / 2,
+                               &line->text->value[offset]);
+                    break;
+                case 1:
+                case 2: // add text to left footer
+                    mvwaddwstr(stdscr,
+                               LINES - 1, 3,
+                               &line->text->value[offset]);
+                    break;
+            }
         }
 
         // add slide number to right footer
-        mvwprintw(stdscr,
-                  LINES - 1, COLS - int_length(deck->slides) - int_length(sc) - 6,
-                  "%d / %d", sc, deck->slides);
+        switch(slidenum) {
+            case 1: // show slide number only
+                mvwprintw(stdscr,
+                          LINES - 1, COLS - int_length(sc) - 3,
+                          "%d", sc);
+                break;
+            case 2: // show current slide & number of slides
+                mvwprintw(stdscr,
+                          LINES - 1, COLS - int_length(deck->slides) - int_length(sc) - 6,
+                          "%d / %d", sc, deck->slides);
+                break;
+        }
 
-        // make header + fooder visible
-        wrefresh(content);
-        wrefresh(stdscr);
+        // copy changed lines in main window to virtual screen
+        wnoutrefresh(stdscr);
 
         line = slide->line;
-        l = 0;
+        l = stop = 0;
 
         // print lines
         while(line) {
             add_line(content, l, (COLS - max_cols) / 2, line, max_cols, colors);
+
+            // raise stop counter if we pass a line having a stop bit
+            if(CHECK_BIT(line->bits, IS_STOP))
+                stop++;
+
             l += (line->length / COLS) + 1;
             line = line->next;
+
+            // only stop here if we didn't stop here recently
+            if(stop > slide->stop)
+                break;
         }
 
-        int i, ymax;
-        getmaxyx( content, ymax, i );
-        for (i = 0; i < url_get_amount(); i++) {
-            mvwprintw(content, ymax - url_get_amount() - 1 + i, 3,
-                      "[%d] ", i);
-            waddwstr(content, url_get_target(i));
+        // print pandoc URL references
+        // only if we already printed all lines of the current slide
+        if(!line) {
+            int i, ymax;
+            getmaxyx( content, ymax, i );
+            for (i = 0; i < url_get_amount(); i++) {
+                mvwprintw(content, ymax - url_get_amount() - 1 + i, 3,
+                          "[%d] ", i);
+                waddwstr(content, url_get_target(i));
+            }
         }
 
-        // make content visible
-        wrefresh(content);
+        // copy changed lines in content window to virtual screen
+        wnoutrefresh(content);
+
+        // compare virtual screen to physical screen and does the actual updates
+        doupdate();
 
         // fade in
         if(fade)
@@ -326,7 +365,7 @@ int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reloa
         i = 0;
         switch(c) {
 
-            // show previous slide
+            // show previous slide or stop bit
             case KEY_UP:
             case KEY_LEFT:
             case KEY_PPAGE:
@@ -335,15 +374,27 @@ int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reloa
             case 263: // BACKSPACE (getty)
             case 'h':
             case 'k':
-                if(slide->prev) {
-                    slide = slide->prev;
-                    sc--;
-                } else {
+                if(stop > 1 || (stop == 1 && !line)) {
+                    // show current slide again
+                    // but stop one stop bit earlier
+                    slide->stop--;
                     fade = false;
+                } else {
+                    if(slide->prev) {
+                        // show previous slide
+                        slide = slide->prev;
+                        sc--;
+                        //stop on first bullet point always
+                        if(slide->stop > 0)
+                            slide->stop = 0;
+                    } else {
+                        // do nothing
+                        fade = false;
+                    }
                 }
                 break;
 
-            // show next slide
+            // show next slide or stop bit
             case KEY_DOWN:
             case KEY_RIGHT:
             case KEY_NPAGE:
@@ -351,11 +402,20 @@ int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reloa
             case ' ':  // SPACE
             case 'j':
             case 'l':
-                if(slide->next) {
-                    slide = slide->next;
-                    sc++;
-                } else {
+                if(stop && line) {
+                    // show current slide again
+                    // but stop one stop bit later (or at end of slide)
+                    slide->stop++;
                     fade = false;
+                } else {
+                    if(slide->next) {
+                        // show next slide
+                        slide = slide->next;
+                        sc++;
+                    } else {
+                        // do nothing
+                        fade = false;
+                    }
                 }
                 break;
 
@@ -458,16 +518,26 @@ int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reloa
 
 void add_line(WINDOW *window, int y, int x, line_t *line, int max_cols, int colors) {
 
-    if(!line->text->text) {
-        return;
-    }
-
     int i; // increment
     int offset = 0; // text offset
 
     // move the cursor in position
     wmove(window, y, x);
 
+    if(!line->text->value) {
+
+        // fill rest off line with spaces if we are in a code block
+        if(CHECK_BIT(line->bits, IS_CODE) && colors) {
+            if(colors)
+                wattron(window, COLOR_PAIR(CP_BLACK));
+            for(i = getcurx(window) - x; i < max_cols; i++)
+                wprintw(window, "%s", " ");
+        }
+
+        // do nothing
+        return;
+    }
+
     // IS_UNORDERED_LIST_3
     if(CHECK_BIT(line->bits, IS_UNORDERED_LIST_3)) {
         offset = next_nonblank(line->text, 0);
@@ -486,7 +556,7 @@ void add_line(WINDOW *window, int y, int x, line_t *line, int max_cols, int colo
                 "%s", prompt);
 
         if(!CHECK_BIT(line->bits, IS_CODE))
-            inline_display(window, &line->text->text[offset], colors);
+            inline_display(window, &line->text->value[offset], colors);
 
     // IS_UNORDERED_LIST_2
     } else if(CHECK_BIT(line->bits, IS_UNORDERED_LIST_2)) {
@@ -505,7 +575,7 @@ void add_line(WINDOW *window, int y, int x, line_t *line, int max_cols, int colo
                 "%s", prompt);
 
         if(!CHECK_BIT(line->bits, IS_CODE))
-            inline_display(window, &line->text->text[offset], colors);
+            inline_display(window, &line->text->value[offset], colors);
 
     // IS_UNORDERED_LIST_1
     } else if(CHECK_BIT(line->bits, IS_UNORDERED_LIST_1)) {
@@ -523,21 +593,23 @@ void add_line(WINDOW *window, int y, int x, line_t *line, int max_cols, int colo
                 "%s", prompt);
 
         if(!CHECK_BIT(line->bits, IS_CODE))
-            inline_display(window, &line->text->text[offset], colors);
+            inline_display(window, &line->text->value[offset], colors);
     }
 
     // IS_CODE
     if(CHECK_BIT(line->bits, IS_CODE)) {
 
-        // set static offset for code
-        offset = CODE_INDENT;
+        if (!CHECK_BIT(line->bits, IS_TILDE_CODE)) {
+            // set static offset for code
+            offset = CODE_INDENT;
+        }
 
         // reverse color for code blocks
         if(colors)
             wattron(window, COLOR_PAIR(CP_BLACK));
 
         // print whole lines
-        waddwstr(window, &line->text->text[offset]);
+        waddwstr(window, &line->text->value[offset]);
     }
 
     if(!CHECK_BIT(line->bits, IS_UNORDERED_LIST_1) &&
@@ -547,7 +619,7 @@ void add_line(WINDOW *window, int y, int x, line_t *line, int max_cols, int colo
 
         // IS_QUOTE
         if(CHECK_BIT(line->bits, IS_QUOTE)) {
-            while(line->text->text[offset] == '>') {
+            while(line->text->value[offset] == '>') {
                 // print a reverse color block
                 if(colors) {
                     wattron(window, COLOR_PAIR(CP_BLACK));
@@ -560,11 +632,11 @@ void add_line(WINDOW *window, int y, int x, line_t *line, int max_cols, int colo
 
                 // find next quote or break
                 offset++;
-                if(line->text->text[offset] == ' ')
+                if(line->text->value[offset] == ' ')
                     offset = next_word(line->text, offset);
             }
 
-            inline_display(window, &line->text->text[offset], colors);
+            inline_display(window, &line->text->value[offset], colors);
         } else {
 
             // IS_CENTER
@@ -586,25 +658,28 @@ void add_line(WINDOW *window, int y, int x, line_t *line, int max_cols, int colo
                     wattron(window, A_UNDERLINE);
 
                 // skip hashes
-                while(line->text->text[offset] == '#')
+                while(line->text->value[offset] == '#')
                     offset = next_word(line->text, offset);
 
                 // print whole lines
-                waddwstr(window, &line->text->text[offset]);
+                waddwstr(window, &line->text->value[offset]);
 
                 wattroff(window, A_UNDERLINE);
 
             // no line-wide markdown
             } else {
 
-                inline_display(window, &line->text->text[offset], colors);
+                inline_display(window, &line->text->value[offset], colors);
             }
         }
     }
 
     // fill rest off line with spaces
-    for(i = getcurx(window) - x; i < max_cols; i++)
-        wprintw(window, "%s", " ");
+    // we only need this if the color is inverted (e.g. code-blocks),
+    // to ensure the background fades too
+    if(CHECK_BIT(line->bits, IS_CODE))
+        for(i = getcurx(window) - x; i < max_cols; i++)
+            wprintw(window, "%s", " ");
 
     // reset to default color
     if(colors)
@@ -680,7 +755,7 @@ void inline_display(WINDOW *window, const wchar_t *c, const int colors) {
 
                         if (*i == L'!') i++;
 
-                        if (wcschr(i, L']')[1] == L'(') {
+                        if (wcschr(i, L']')[1] == L'(' && wcschr(i, L')')) {
                             i++;
 
                             // turn higlighting and underlining on
@@ -796,8 +871,11 @@ void fade_out(WINDOW *window, int trans, int colors, int invert) {
                 init_pair(CP_BLACK, 16, white_ramp[i]);
             }
 
-            // refresh window with new color
-            wrefresh(window);
+            // refresh virtual screen with new color
+            wnoutrefresh(window);
+
+            // compare virtual screen to physical screen and does the actual updates
+            doupdate();
 
             // delay for our eyes to recognize the change
             usleep(FADE_DELAY);
@@ -823,8 +901,11 @@ void fade_in(WINDOW *window, int trans, int colors, int invert) {
                 init_pair(CP_BLACK, 16, white_ramp[i]);
             }
 
-            // refresh window with new color
-            wrefresh(window);
+            // refresh virtual screen with new color
+            wnoutrefresh(window);
+
+            // compare virtual screen to physical screen and does the actual updates
+            doupdate();
 
             // delay for our eyes to recognize the change
             usleep(FADE_DELAY);