Skip to content
screen.cc 5.75 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"
#include "options.hh"
Seblu's avatar
Seblu committed

Screen::Screen() {
  *cmd_buffer_ = 0;
  cmd_buf_off_ = 0;
  cmd_win_off_ = 0;
  cmd_history_off_ = 0;
}
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();
  keypad(stdscr, TRUE);

  // refresh parameters (needed by ncurses)
Seblu's avatar
Seblu committed
  refresh();
Seblu's avatar
Seblu committed

void Screen::create_windows() {
Seblu's avatar
Seblu committed
  // Check screen size
  if (LINES < 6 || COLS < 3) {
    std::cerr << "Screen is too small." << std::endl;
    exit(ERR_SCREENSZ);
  }

  noecho();
  clear();
  refresh();
Seblu's avatar
Seblu committed

  // msg window
  if (msg_)
    delwin(msg_);
  msg_ = newwin(LINES - 3, COLS, 0, 0);
  msg_draw();

  // cmd window
  if (cmd_)
    delwin(cmd_);
  cmd_ = newwin(3, COLS, LINES - 3, 0);
  cmd_draw();
}
Seblu's avatar
Seblu committed

void Screen::login() {
  char *buf;
  int size;
  const char *smsg;

  clear();
  box(stdscr, 0,0);
  move(1, 1);

  // ask login
  if (O.login.empty()) {
    smsg = "Login: ";
    size = COLS - 2 - strlen(smsg);
    buf = new char[size + 1];
    echo();
    printw(smsg);
    refresh();
    getnstr(buf, size);
    buf[size] = 0;
    O.login = buf;
    delete [] buf;
    move(2,1);
  }
Seblu's avatar
Seblu committed

  // ask password
  smsg = "Password: ";
  size = COLS - 2 - strlen(smsg);
  buf = new char[size + 1];
  printw(smsg);
  noecho();
  refresh();
  getnstr(buf, size);
  buf[size] = 0;
  O.login = buf;
  delete [] buf;
Seblu's avatar
Seblu committed
}

void Screen::run() {

  //nominal screen nom
  create_windows();

Seblu's avatar
Seblu committed
  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_);
      cmd_win_off_ = 0;
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_);
      cmd_win_off_ = 0;
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 KEY_HOME:
      cmd_buf_off_ = 0;
      break;
    case KEY_END:
      cmd_buf_off_ = strlen(cmd_buffer_);
Seblu's avatar
Seblu committed
    case KEY_RETURN:
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_win_off_ = 0;
Seblu's avatar
Seblu committed
      cmd_history_off_ = 0;
      // print result
      cmd_draw();
Seblu's avatar
Seblu committed
      break;
    case KEY_BACKSPACE:
      if (cmd_buf_off_ != 0)
	if (del_char(cmd_buffer_, cmd_buf_off_ - 1, CMD_BUFFER_SIZE))
	  --cmd_buf_off_;
      cmd_draw();
      break;
    case KEY_DC:
      del_char(cmd_buffer_, cmd_buf_off_, CMD_BUFFER_SIZE);
      cmd_draw();
      break;
    case KEY_RESIZE:
      create_windows();
Seblu's avatar
Seblu committed
      break;
Seblu's avatar
Seblu committed
    case KEY_EOF:
      // save history
      return;
Seblu's avatar
Seblu committed
    default:
Seblu's avatar
Seblu committed
      if (!isprint(key)) break;
      if (add_char(key, cmd_buffer_, cmd_buf_off_, CMD_BUFFER_SIZE))
	++cmd_buf_off_;
Seblu's avatar
Seblu committed

void Screen::cmd_draw() {
Seblu's avatar
Seblu committed
  char print_buf[CMD_BUFFER_SIZE];

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

  // check cur pos is in screen
Seblu's avatar
Seblu committed
  if (cmd_buf_off_ + 1 > (size_t) COLS - 2 + cmd_win_off_)
    cmd_win_off_ = cmd_buf_off_ + 1 - (COLS - 2) ;
  else if (cmd_buf_off_ < cmd_win_off_)
    cmd_win_off_ = cmd_buf_off_;
Seblu's avatar
Seblu committed

  // copy part of buffer in print buffer
  size_t minsize = (CMD_BUFFER_SIZE < COLS - 2) ? CMD_BUFFER_SIZE : COLS - 2;
  strncpy(print_buf, cmd_buffer_ + cmd_win_off_, minsize);
  print_buf[minsize - 1] = 0;
Seblu's avatar
Seblu committed

  // 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_ - cmd_win_off_);
Seblu's avatar
Seblu committed
  wrefresh(cmd_);
}

void Screen::msg_draw() {
  werase(msg_);
  box(msg_, 0, 0);
  wrefresh(msg_);
}

/*!
** Add a char in a buffer
**
** @param c char to add
** @param offset where add in the buffer
*/
bool Screen::add_char(char c, char *string, ssize_t offset, size_t buf_len) {
Seblu's avatar
Seblu committed
  assert(string);
  size_t len = strlen(string);

  // check if add one char is in range
  if (len + 1 > buf_len - 1)
    return false;
Seblu's avatar
Seblu committed

  // check if offset is good
  if (offset >= (ssize_t) buf_len - 1 || offset < 0)
    return false;
Seblu's avatar
Seblu committed

  // move one char every char
  for (ssize_t i = len; i >= offset; --i)
    string[i + 1] = string[i];
  string[offset] = c;
  return true;
Seblu's avatar
Seblu committed
}

bool Screen::del_char(char *string, ssize_t offset, size_t buf_len) {
Seblu's avatar
Seblu committed
  assert(string);
  size_t len = strlen(string);

  // check if del one char is possible
  if (len == 0)
    return false;
Seblu's avatar
Seblu committed

  // check if offset is good
  if (offset >= (ssize_t) buf_len - 1 || offset < 0)
    return false;
Seblu's avatar
Seblu committed

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

  return true;
Seblu's avatar
Seblu committed
}

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;
}