Browse Source

Render is now a class. Need tests.

bugz 4 years ago
parent
commit
c93c05f06d
2 changed files with 391 additions and 278 deletions
  1. 356 278
      render.cpp
  2. 35 0
      render.h

+ 356 - 278
render.cpp

@@ -1,15 +1,370 @@
 #include "render.h"
 #include "terminal.h"
+#include "utils.h"
 #include "zf_log.h"
 #include <ctype.h>
+#include <sstream>
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
 #include <unistd.h> // usleep
 #include <vector>
 
+// Does this copy the terminal?
+
+Render::Render(int fd, Terminal &term) : term(term) {
+  this->fd = fd;
+  reset();
+}
+
+void Render::reset(void) {
+  speed = 0;
+  effect = 0;
+  overlimit = 0;
+  image_data = nullptr; // FUTURE: vector
+  image_size = 0; // FUTURE: vector
+}
+
+void Render::set_image(const char **lines, int size) {
+  image_data = lines;
+  image_size = size;
+}
+
+void Render::reset_image(void) {
+  image_data = nullptr;
+  image_size = 0;
+}
+
+void Render::sleep(void) {
+  if (overlimit)
+    return;
+
+  if (speed) { // * 100 still too slow.
+    ms_sleep(speed * 10);
+  }
+}
+
+int Render::ms_sleep(unsigned int ms) {
+  int result = 0;
+  struct timespec ts = {ms / 1000, (ms % 1000) * 1000000L};
+
+  do {
+    struct timespec ts_sleep = ts;
+    result = nanosleep(&ts_sleep, &ts);
+  } while ((-1 == result));
+  return result;
+}
+
+void Render::color(int color) {
+  const int MYSTIC[] = {0, 4, 2, 6, 1, 5, 3, 7};
+  std::ostringstream oss;
+
+  switch (color) {
+  case 0:
+  case 1:
+  case 2:
+  case 3:
+  case 4:
+  case 5:
+  case 6:
+  case 7:
+    oss << "\x1b[0;" << MYSTIC[color] + 30 << "m";
+    break;
+  case 8:
+  case 9:
+  case 10:
+  case 11:
+  case 12:
+  case 13:
+  case 14:
+  case 15:
+    oss << "\x1b[0;1;" << MYSTIC[color] + 30 << "m";
+    break;
+  case 16:
+  case 17:
+  case 18:
+  case 19:
+  case 20:
+  case 21:
+  case 22:
+  case 23:
+    oss << "\x1b[" << MYSTIC[color] + 40 << "m";
+    break;
+  case 24:
+  case 25:
+  case 26:
+  case 27:
+  case 28:
+  case 29:
+  case 30:
+  case 31:
+    oss << "\x1b[5;" << MYSTIC[color] + 40 << "m";
+    break;
+  default:
+    break;
+  }
+  std::string buffer = oss.str();
+  ZF_LOGD("write_color( %d ): %s", color, repr(buffer.c_str()));
+  write(fd, buffer.c_str(), buffer.size());
+}
+
+void Render::pos_goto(int x, int y) {
+  std::ostringstream oss;
+
+  oss << "\x1b[" << y << ";" << x << "H";
+  std::string buffer = oss.str();
+  write(fd, buffer.c_str(), buffer.size());
+};
+
+void Render::send(char ch) { // render_effect
+  // int effect = effect;
+  int l;
+  char space = ' ';
+  char bs = '\b';
+  Terminal::termchar tc;
+
+  tc = term.putchar(ch);
+  if (tc.in_ansi) {
+    // We are inside ANSI command, so
+    write(fd, &ch, 1);
+    return;
+  }
+
+  switch (effect) {
+  case 1:
+    // CHAR + SPC + BS
+    render_sleep();
+    write(fd, &ch, 1);
+    render_sleep();
+    write(fd, &space, 1);
+    render_sleep();
+    render_sleep();
+    write(fd, &bs, 1);
+    break;
+  case 2:
+    // CHAR + 8 spaces + 8 BS
+    // This might be too much.
+#define MOVE 4
+    render_sleep();
+    write(fd, &ch, 1);
+    for (l = 0; l < MOVE; l++) {
+      render_sleep();
+      write(fd, &space, 1);
+    }
+    for (l = 0; l < MOVE; l++) {
+      render_sleep();
+      write(fd, &bs, 1);
+    }
+    break;
+  case 0:
+  default:
+    // NORMAL
+    render_sleep();
+    write(fd, &ch, 1);
+    break;
+  }
+}
+
+void Render::send(std::string &string_out) { // render
+  time_t start = time(NULL);
+  size_t pos = 0;
+  int elapsed;
+  size_t tpos;
+
+  while ((tpos = string_out.find(TRIGGER, pos)) != std::string::npos) {
+    while (pos != tpos) {
+      elapsed = time(NULL) - start;
+      if (elapsed > SLEEP_LIMIT) {
+        overlimit = 1;
+        speed = 0;
+      }
+
+      send(string_out[pos]);
+      pos++;
+    }
+
+    pos += strlen(TRIGGER);
+    process_trigger(string_out, pos);
+  }
+
+  while (pos < string_out.size()) {
+    elapsed = time(NULL) - start;
+    if (elapsed > SLEEP_LIMIT) {
+      overlimit = 1;
+      speed = 0;
+    }
+
+    send(string_out[pos]);
+    pos++;
+  }
+}
+
+int Render::digit(std::string str, size_t &pos, int digits) {
+  int i = 0;
+
+  while (digits > 0) {
+    if (std::isdigit(str[pos])) {
+      i *= 10;
+      i += str[pos] - '0';
+      pos++;
+    } else {
+      ZF_LOGE("digit fail");
+    }
+    digits--;
+  };
+  return i;
+}
+
+void Render::process_trigger(std::string str, size_t &pos) {
+  char ch = str[pos];
+  int i, x, y;
+  pos++;
+  switch (ch) {
+  case 'D':
+    i = digit(str, pos, 2);
+
+    if ((i > 0) && (i < 80)) {
+      ZF_LOGI("DEL %02d", i);
+
+      for (x = 0; x < i; x++) {
+        write(fd, "\b \b", 3);
+        term.putstring("\b \b");
+      }
+    };
+    break;
+
+  case 'C': {
+    i = 0;
+    if (str[pos] == 'S') {
+      pos++;
+      color_history.push_back(term.color_restore());
+      // console_history.push_back(console);
+      ZF_LOGI("saved color.");
+      break;
+    }
+    if (str[pos] == 'R') {
+      pos++;
+      if (color_history.empty()) {
+        ZF_LOGE("Trying to Color Restore from empty vector!");
+        break;
+      }
+      std::string restore = color_history.back();
+      color_history.pop_back();
+      write(fd, restore.c_str(), restore.size());
+      break;
+    }
+    i = digit(str, pos, 2);
+    write_color(fd, i);
+  } break;
+
+  // no longer takes a filename.  :)
+  case 'F':
+  case 'f': {
+    int UsePos = 0;
+    if (ch == 'f') {
+      UsePos = 1;
+      x = digit(str, pos, 2);
+      y = digit(str, pos, 2);
+      ZF_LOGI("file at (%d, %d)", x, y);
+    }
+    ZF_LOGD("IMAGE (%d lines)", image_size);
+    if (UsePos) {
+      send_image(x, y);
+    } else {
+      send_image();
+    };
+  } break;
+
+  case 'G': {
+    x = digit(str, pos, 2);
+    y = digit(str, pos, 2);
+    char buffer[20]; // row ; column H
+    int slen;
+    ZF_LOGD("GOTO (%d,%d)", x, y);
+    slen = snprintf(buffer, sizeof(buffer), "\x1b[%d;%dH", y, x);
+    if (slen >= (int)sizeof(buffer)) {
+      ZF_LOGE("snprintf %d > size %d", slen, (int)sizeof(buffer));
+      buffer[0] = 0;
+    }
+    write(fd, buffer, strlen(buffer));
+  } break;
+
+  case 'R': {
+    i = digit(str, pos);
+    if ((i > 0) && (i < 10)) {
+      ZF_LOGI("RENDER %d", i);
+      effect = i;
+    } else {
+      effect = 0;
+    }
+  } break;
+  case 'S': {
+    i = digit(str, pos);
+    if ((i > 0) && (i < 10)) {
+      ZF_LOGI("SPEED %d", i);
+      speed = i;
+    } else {
+      speed = 0;
+    }
+  } break;
+  case 'P': {
+    i = digit(str, pos);
+    if ((i > 0) && (i < 10)) {
+      ZF_LOGI("PAWS %d", i);
+      // sleep(i);
+      if (!overlimit) {
+        // sleep(i);
+        ms_sleep(i * 1000);
+      };
+    }
+  } break;
+  }
+}
+
+int Render::send_image(int x, int y) {
+  int i;
+  const char **lines = image_data;
+
+  if (lines == nullptr) {
+    ZF_LOGE("No image data for send_image(%d,%d)", x, y);
+    return 0;
+  }
+
+  for (i = 0; i < image_size; i++) {
+    send_goto(fd, x, y);
+    y++;
+    write(fd, lines[i], strlen(lines[i]));
+  }
+
+  // success
+  reset_image();
+  return 1;
+}
+
+int Render::send_image(void) {
+  int i;
+  const char **lines = image_data;
+
+  if (lines == nullptr) {
+    ZF_LOGE("No image data for send_image.");
+    return 0;
+  }
+
+  for (i = 0; i < image_size; i++) {
+    std::string line(lines[i]);
+    line.append("\r\n");
+    // rendering the ^BAT^ was a bad idea. (uses ^ chars).
+    // render(fd, line);
+    write(fd, lines[i], strlen(lines[i]));
+    write(fd, "\r\n", 2);
+  }
+
+  // success
+  reset_image();
+  return 1;
+}
+
 extern const char *strnstr(const char *source, int len, const char *needle);
-extern const char *repr(const char *data);
 extern struct console_details console;
 
 struct render current_render;
@@ -245,58 +600,6 @@ int send_image(int fd, int x, int y) {
   return 1;
 }
 
-#ifdef UNWANTED
-int send_file(int fd, char *filename) {
-  FILE *fp;
-  char buffer[100];
-  int read;
-
-  fp = fopen(filename, "rb");
-  if (fp == NULL) {
-    ZF_LOGD("Failed to open %s", filename);
-    return 0;
-  }
-
-  while ((read = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
-    write(fd, buffer, read);
-  };
-  fclose(fp);
-  return 1;
-}
-
-int send_file(int fd, int x, int y, char *filename) {
-  FILE *fp;
-  char buffer[100];
-  int read;
-
-  fp = fopen(filename, "rb");
-  if (fp == NULL) {
-    ZF_LOGD("Failed to open %s", filename);
-    return 0;
-  }
-
-  send_goto(fd, x, y);
-  y++;
-
-  while ((read = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
-    char *cp, *last_cp;
-
-    buffer[read] = 0;
-    last_cp = buffer;
-    while ((cp = strchr(last_cp, '\n')) != NULL) {
-      *cp = 0;
-      write(fd, last_cp, strlen(last_cp));
-      send_goto(fd, x, y);
-      y++;
-      last_cp = cp + 1;
-    };
-    write(fd, last_cp, strlen(last_cp));
-  };
-  fclose(fp);
-  return 1;
-}
-#endif
-
 int digit(std::string str, size_t &pos, int digits = 1) {
   int i = 0;
 
@@ -429,170 +732,6 @@ void process_trigger(int fd, std::string str, size_t &pos) {
   }
 }
 
-#ifdef UNWANTED
-/**
- * process_trigger( fd, *cp )
- *
- * This process a command trigger.
- * It has seen TRIGGER, and now it is
- * processing whatever comes after it.
- * It will perform the process, and
- * return the char * of whatever is next.
- */
-const char *process_trigger(int fd, const char *cp) {
-  char ch;
-  int i, x, y;
-  ch = *cp;
-  cp++;
-
-  switch (ch) {
-  case 'D':
-    i = 0;
-    if (isdigit(*cp)) {
-      i = (*cp) - '0';
-      cp++;
-    };
-    if (isdigit(*cp)) {
-      i *= 10;
-      i += (*cp) - '0';
-      cp++;
-    };
-
-    if ((i > 0) && (i < 80)) {
-      ZF_LOGI("DEL %02d", i);
-
-      for (x = 0; x < i; x++) {
-        write(fd, "\b \b", 3);
-        console_receive(&console, "\b \b");
-      }
-    };
-    break;
-
-  case 'C': {
-    i = 0;
-    if (*cp == 'R') {
-      cp++;
-      const char *restore = color_restore(&console);
-      write(fd, restore, strlen(restore));
-      break;
-    }
-    if (isdigit(*cp)) {
-      i = (*cp) - '0';
-      cp++;
-    };
-    if (isdigit(*cp)) {
-      i *= 10;
-      i += (*cp) - '0';
-      cp++;
-    };
-    write_color(fd, i);
-  } break;
-
-  // no longer takes a filename.  :)
-  case 'F':
-  case 'f': {
-    int pos = 0;
-    if (ch == 'f') {
-      pos = 1;
-      x = (*cp) - '0';
-      cp++;
-      x *= 10;
-      x += (*cp) - '0';
-      cp++;
-      y = (*cp) - '0';
-      cp++;
-      y *= 10;
-      y += (*cp) - '0';
-      cp++;
-      ZF_LOGI("file at (%d, %d)", x, y);
-    }
-    ZF_LOGD("IMAGE (%d lines)", image_size);
-    if (pos) {
-      send_image(fd, x, y);
-    } else {
-      send_image(fd);
-    };
-  } break;
-
-  case 'G': {
-    x = 0;
-    if (isdigit(*cp)) {
-      x = (*cp) - '0';
-      cp++;
-    };
-    if (isdigit(*cp)) {
-      x *= 10;
-      x += (*cp) - '0';
-      cp++;
-    };
-    y = 0;
-    if (isdigit(*cp)) {
-      y = (*cp) - '0';
-      cp++;
-    };
-    if (isdigit(*cp)) {
-      y *= 10;
-      y += (*cp) - '0';
-      cp++;
-    };
-    char buffer[20]; // row ; column H
-    int slen;
-    ZF_LOGD("GOTO (%d,%d)", x, y);
-    slen = snprintf(buffer, sizeof(buffer), "\x1b[%d;%dH", y, x);
-    if (slen >= (int)sizeof(buffer)) {
-      ZF_LOGE("snprintf %d > size %d", slen, (int)sizeof(buffer));
-      buffer[0] = 0;
-    }
-    write(fd, buffer, strlen(buffer));
-  } break;
-
-  case 'R': {
-    i = 0;
-    if (isdigit(*cp)) {
-      i = (*cp) - '0';
-      cp++;
-    };
-    if ((i > 0) && (i < 10)) {
-      ZF_LOGI("RENDER %d", i);
-      current_render.effect = i;
-    } else {
-      ZF_LOGI("RENDER OFF");
-      current_render.effect = 0;
-    }
-  } break;
-  case 'S': {
-    i = 0;
-    if (isdigit(*cp)) {
-      i = (*cp) - '0';
-      cp++;
-    };
-    if ((i > 0) && (i < 10)) {
-      ZF_LOGI("SPEED %d", i);
-      current_render.speed = i;
-    } else {
-      ZF_LOGI("SPEED OFF");
-      current_render.speed = 0;
-    }
-  } break;
-  case 'P': {
-    i = 0;
-    if (isdigit(*cp)) {
-      i = (*cp) - '0';
-      cp++;
-    };
-    if ((i > 0) && (i < 10)) {
-      ZF_LOGI("PAWS %d", i);
-      // sleep(i);
-      if (!render_overlimit) {
-        sleep(i);
-      };
-    }
-  } break;
-  }
-  return cp;
-}
-#endif
-
 /**
  * render_effect( fd, ch )
  *
@@ -649,67 +788,6 @@ void render_effect(int fd, char ch) {
   }
 }
 
-#ifdef UNWANTED
-/**
- * render( fd, string_out )
- *
- * Render an entire string.
- * Handles TRIGGER.
- * Renders with effects.
- */
-void render(int fd, const char *string_out, int len) {
-  const char *cp = string_out;
-  const char *trigger = cp;
-
-  time_t start = time(NULL);
-  int elapsed;
-  int over = 0;
-
-  reset_render();
-
-  // ZF_LOGV("render(%d, %s)", fd, repr(string_out));
-  ZF_LOGV_MEM(string_out, len, "render(%d, %d bytes):", fd, len);
-
-  // Check our time from time to time.
-  // If we start running long, disable sleeps.
-
-  while ((trigger = strnstr(cp, len - (cp - string_out), TRIGGER)) != NULL) {
-    // There is special things to handle in here.
-    while (cp != trigger) {
-      elapsed = time(NULL) - start;
-      if (elapsed > SLEEP_LIMIT) {
-        render_overlimit = 1;
-        current_render.speed = 0;
-      };
-
-      // write(fd, cp, 1 );
-      render_effect(fd, *cp);
-      cp++;
-    };
-
-    // ZF_LOGI( "at trigger: (%s)", cp);
-    cp += strlen(TRIGGER);
-
-    // Ok, we're pointing at the trigger -- do something.
-    cp = process_trigger(fd, cp);
-
-    // ZF_LOGI( "after trigger: (%s)", cp);
-  };
-
-  // We still might be under a rendering effect.
-  while (cp < (string_out + len)) {
-    elapsed = time(NULL) - start;
-    if (elapsed > SLEEP_LIMIT) {
-      render_overlimit = 1;
-      current_render.speed = 0;
-    };
-    // write(fd, cp, 1);
-    render_effect(fd, *cp);
-    cp++;
-  }
-}
-#endif
-
 /**
  * render( fd, string_out )
  *

+ 35 - 0
render.h

@@ -1,7 +1,42 @@
 #ifndef RENDER_H
 #define RENDER_H
 
+#include "terminal.h"
 #include <string>
+#include <vector>
+
+class Render {
+private:
+  int speed;
+  int effect;
+  int fd;
+  int overlimit;
+  Terminal &term;
+  std::vector<std::string> color_history;
+  const char **image_data; // vector to hold multiple images -- just in case.
+  int image_size;
+
+public:
+  Render(int fd, Terminal &term);
+  void reset(void);
+  void sleep(void);
+  int ms_sleep(unsigned int ms);
+  void color(int color);
+  void pos_goto(int x, int y);
+
+  void send(char ch);                 // render_effect
+  void send(std::string &string_out); // render
+
+  // to change:  Make this a vector (in the case we set multiple images)
+  void set_image(const char **lines, int size); // render_image
+  void reset_image(void);
+
+private:
+  void process_trigger(std::string str, size_t &pos);
+  int digit(std::string str, size_t &pos, int digits = 1);
+  int send_image(int x, int y);
+  int send_image(void);
+};
 
 struct render {
   int speed;