Refactored client-side rendering code to use a Color struct rather than raw float arrays.
134 lines
3.7 KiB
C++
134 lines
3.7 KiB
C++
#include <cstdio>
|
|
#include <SDL3/SDL.h>
|
|
#include <GL/glew.h>
|
|
#include <SDL3/SDL_events.h>
|
|
|
|
#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);
|
|
}
|