Skip to content
screen.cc 4.11 KiB
Newer Older
Seblu's avatar
Seblu committed
#include <ctype.h>
#include <signal.h>

Seblu's avatar
Seblu committed
#include "slc.hh"
#include "screen.hh"
Seblu's avatar
Seblu committed
#include "history.hh"
Seblu's avatar
Seblu committed

Seblu's avatar
Seblu committed
Screen::Screen() {}
Seblu's avatar
Seblu committed

void Screen::init() {
  // Init ncurses
  initscr();

  // register end stop ncurses before exit
  atexit((void (*)(void)) endwin);

  // Set good parameters
  cbreak();
  noecho();
  keypad(stdscr, TRUE);

  refresh();

  //wrefresh(stdscr);
  // Get term dimension
  int row, col;
  getmaxyx(stdscr, row, col);

  // Create msg window
  msg_ = newwin(row - 3, col, 0, 0);
  box(msg_, 0, 0);
  wrefresh(msg_);

  // Create cmd window
  cmd_ = newwin(3, col, row - 3, 0);
  box(cmd_, 0 , 0);

Seblu's avatar
Seblu committed
  // set buf value
  *cmd_buffer_ = 0;
  cmd_buf_off_ = 0;
  cmd_buf_win_off_ = 0;
  cmd_buf_win_size_ = col - 1;
  cmd_history_off_ = 0;

Seblu's avatar
Seblu committed
  wmove(cmd_, 1, 1);
  wrefresh(cmd_);

Seblu's avatar
Seblu committed
  //register sigwinch

Seblu's avatar
Seblu committed
}

void Screen::run() {
  while (1) {
Seblu's avatar
Seblu committed
    int key = getch();
Seblu's avatar
Seblu committed
    switch(key) {
Seblu's avatar
Seblu committed
      // KEY UP
    case KEY_UP:
      if (cmd_history_off_ + 1 > H.size())
	break;
      if (cmd_history_off_ == 0)
	memcpy(cmd_history_buffer_, cmd_buffer_, CMD_BUFFER_SIZE);
      strncpy(cmd_buffer_, H.get(cmd_history_off_++).c_str(), CMD_BUFFER_SIZE);
      cmd_buffer_[CMD_BUFFER_SIZE - 1] = 0;
      cmd_buf_off_ = strlen(cmd_buffer_);
Seblu's avatar
Seblu committed
      break;
      // KEY DOWN
    case KEY_DOWN:
      if (cmd_history_off_ == 0)
	break;
      --cmd_history_off_;
      if (cmd_history_off_ == 0)
	memcpy(cmd_buffer_, cmd_history_buffer_, CMD_BUFFER_SIZE);
      else {
	strncpy(cmd_buffer_, H.get(cmd_history_off_ - 1).c_str(), CMD_BUFFER_SIZE);
	cmd_buffer_[CMD_BUFFER_SIZE - 1] = 0;
      }
      cmd_buf_off_ = strlen(cmd_buffer_);
Seblu's avatar
Seblu committed
      break;
      // KEY LEFT
Seblu's avatar
Seblu committed
    case KEY_LEFT:
Seblu's avatar
Seblu committed
      if (cmd_buf_off_ > 0)
	--cmd_buf_off_;
Seblu's avatar
Seblu committed
      break;
Seblu's avatar
Seblu committed
      // KEY RIGHT
Seblu's avatar
Seblu committed
    case KEY_RIGHT:
Seblu's avatar
Seblu committed
      if ((size_t) cmd_buf_off_ < strlen(cmd_buffer_))
	++cmd_buf_off_;
Seblu's avatar
Seblu committed
      break;
    case 10:
Seblu's avatar
Seblu committed
      // save buffer in history
      H.add(cmd_buffer_);
      // send buffer
      wprintw(msg_, "%s\n", cmd_buffer_);
      wrefresh(msg_);
      // purge buffer
      *cmd_buffer_ = 0;
      cmd_buf_off_ = 0;
      cmd_buf_win_off_ = 0;
      cmd_history_off_ = 0;
Seblu's avatar
Seblu committed
      break;
    case KEY_BACKSPACE:
Seblu's avatar
Seblu committed
      if (cmd_buf_off_ == 0) break;
      del_char(cmd_buffer_, --cmd_buf_off_, CMD_BUFFER_SIZE);
Seblu's avatar
Seblu committed
      break;
    default:
Seblu's avatar
Seblu committed
      if (!isprint(key)) break;
      if (cmd_buf_off_ >= CMD_BUFFER_SIZE - 1) break;
      add_char(key, cmd_buffer_, cmd_buf_off_++, CMD_BUFFER_SIZE);
Seblu's avatar
Seblu committed
    }
Seblu's avatar
Seblu committed
    draw_cmd();
Seblu's avatar
Seblu committed

void Screen::draw_cmd() {
  char print_buf[CMD_BUFFER_SIZE];

  // clean and redraw the cmd box
  werase(cmd_);
  box(cmd_, 0, 0);
  wmove(cmd_, 1, 1);

  // compute offset
  if ((ssize_t) cmd_buf_off_ - cmd_buf_win_off_ > cmd_buf_win_size_)
    ++cmd_buf_win_off_;

  // copy part of buffer in print buffer
  strncpy(print_buf, cmd_buffer_ + cmd_buf_win_off_, cmd_buf_win_size_ - 2);
  print_buf[cmd_buf_win_size_ - 1] = 0;

  // print print buffer
  wattron(cmd_, A_BOLD);
  wprintw(cmd_, "%s", print_buf);
  wattroff(cmd_, A_BOLD);

  // move cursor to right pos
  wmove(cmd_, 1, 1 + cmd_buf_off_);
  wrefresh(cmd_);
}

void Screen::add_char(char c, char *string, ssize_t offset, size_t buf_len) {
  assert(string);
  size_t len = strlen(string);

  // check if add one char is possible
  if (len + 1 >= buf_len - 1)
    return;

  // check if offset is good
  if (offset >= (ssize_t) buf_len - 1 || offset < 0)
    return;

  // move one char every char
  for (ssize_t i = len; i >= offset; --i)
    string[i + 1] = string[i];
  string[offset] = c;
}

void Screen::del_char(char *string, ssize_t offset, size_t buf_len) {
  assert(string);
  size_t len = strlen(string);

  // check if del one char is possible
  if (len == 0)
    return;

  // check if offset is good
  if (offset >= (ssize_t) buf_len - 1 || offset < 0)
    return;

  // move one char every char
  for (; string[offset] != 0; ++offset)
    string[offset] = string[offset + 1];
}

void sigwinch(int) {
  return;
}

Screen &operator<< (Screen &scr, const string &s) {
  wprintw(scr.msg_, "%s", s.c_str());
  wrefresh(scr.msg_);
  return scr;
}

Screen &operator<< (Screen &scr, int i) {
  wprintw(scr.msg_, "%d", i);
  wrefresh(scr.msg_);
  return scr;
}