#include #include #include #include #include "terminal.h" #include "client_network.h" #include "gfx/txt_renderer.h" #include "gfx/types.h" Terminal::Terminal(ClientNetwork* network) : _network(network) { /* Placeholder welcome message to history. */ _should_close = false; _scroll_offset = 0; _prompt = ""; } Terminal::~Terminal(void) {} void Terminal::update(void) { } void Terminal::add_history(const std::string& line) { std::string line_with_spaces; for(char ch : line) { if(ch == '\t') { line_with_spaces += " "; } else { line_with_spaces += ch; } } _history.push_back(line_with_spaces); if(line == "__CLOSE_CONNECTION__") { _history.back() = "Connection closed by server."; _should_close = true; } } void Terminal::set_prompt(const std::string& prompt) { _prompt = prompt; } bool Terminal::close(void) { return _should_close; } void Terminal::_on_ret_press(void) { std::string command = _input_buffer; _input_buffer.clear(); /* Clear the input buffer immediately. */ /* Add the command to history. */ _history.push_back(_prompt + "> " + command); if(command == "clear") { _history.clear(); return; } _network->send(command); /* TODO: Ugly hack. Refactor to pass window height * We need the window height to know if we should * auto-scroll, but we don't have it here. * Assume the height of 500 for now. */ int visible_lines = (500-5.0f)/20.0f; /* Subtract padding. */ if((int)_history.size()+1 > visible_lines) { _scroll_offset = (_history.size()+1) - visible_lines+1; } } void Terminal::handle_input(SDL_Event* event) { if(event->type == SDL_EVENT_TEXT_INPUT) { /* Append chars to the input buffer. */ _input_buffer += event->text.text; } else if(event->type == SDL_EVENT_KEY_DOWN) { /* Handle special keys. */ if(event->key.key == SDLK_BACKSPACE && _input_buffer.length() > 0) { _input_buffer.pop_back(); } else if(event->key.key == SDLK_RETURN) { _on_ret_press(); } } } void Terminal::scroll(int amount, int win_content_height) { /* amount > 0 = scroll up. amount < 0 = scroll down. */ _scroll_offset += amount; /* Lower bound: Don't scroll below the top of the history. */ if(_scroll_offset < 0) { _scroll_offset = 0; } /* Upper bound: Don't scroll past the last command. */ float line_height = 20.0f; int visible_lines = win_content_height / line_height; int max_scroll = (_history.size()+1) - visible_lines; if(max_scroll < 0) max_scroll = 0; if(_scroll_offset > max_scroll) { _scroll_offset = max_scroll; } } void Terminal::render(TextRenderer* renderer, int x, int y, int width, int height, bool show_cursor) { const Color white = { 1.0f, 1.0f, 1.0f }; const Color green = { 0.2f, 1.0f, 0.2f }; float line_height = 20.0f; float padding = 5.0f; /* Enable scissor test to clip rendering to the window content area. */ glEnable(GL_SCISSOR_TEST); glScissor(x, y, width, height); /* Draw History. */ for(size_t i = _scroll_offset; i < _history.size(); ++i) { float y_pos = (y+height) - padding - line_height - ((i - _scroll_offset) * line_height); renderer->render_text(_history[i].c_str(), x+padding, y_pos, 1.0f, white); } /* Draw current input line. */ std::string line_to_render = _prompt + "> " + _input_buffer; if(show_cursor) { line_to_render += "_"; } float prompt_y_pos = (y+height) - padding - line_height - ((_history.size()-_scroll_offset)*line_height); renderer->render_text(line_to_render.c_str(), x+padding, prompt_y_pos, 1.0f, green); /* Disable scissor test. */ glDisable(GL_SCISSOR_TEST); }