Rev 2302 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* console.cc
* DIN Is Noise is copyright (c) 2006-2025 Jagannathan Sampath
* DIN Is Noise is released under GNU Public License 2.0
* For more information, please visit https://dinisnoise.org/
*/
#include <algorithm>
#include <string>
using namespace std;
#include "console.h"
#include "font.h"
#include "input.h"
#include "command.h"
#include "tcl_interp.h"
#include "tokenizer.h"
#include "globals.h"
#include "ui_list.h"
#include "log.h"
extern cmdlist cmdlst;
extern char BUFFER [];
extern int line_height;
void console::add_line (const mesg& ln) {
lines.push_back (ln);
++nlines;
if (nlines > maxlines) {
lines.pop_front ();
--nlines;
}
last ();
}
void console::last () { // ensures last line is always displayed
end ();
if (rollup_ == 0) up (lines_per_screen - 1);
}
void console::end () {
startl = std::max (0, nlines - 1);
calc_startl_iterator ();
}
void console::up (int i) {
startl = std::max (0, startl - i);
calc_startl_iterator ();
}
void console::down (int i) {
startl += i;
if (startl >= nlines) startl = std::max (0, nlines - 1);
calc_startl_iterator ();
}
void console::pgdn () {
down (lines_per_screen);
}
void console::pgup () {
up (lines_per_screen);
}
void console::home () {
startl = 0;
calc_startl_iterator ();
}
console::console () : b_roll (10, arrow_button::up) {
maxlines = 512;
command_mode = 0;
rollup_ = 0;
curs_loc = 0;
curs_locx = 0;
hid = -1;
clear ();
b_roll.set_listener (this);
history.reserve (1024);
}
console& console::operator<< (const color& c) {
clr = c;
return *this;
}
console& console::operator<< (const string& s) {
cur_line.text += s;
return *this;
}
console& console::operator<< (unsigned int i) {
sprintf (BUFFER, "%x", i);
*this << BUFFER;
return *this;
}
console& console::operator<< (int i) {
sprintf (BUFFER, "%d", i);
*this << BUFFER;
return *this;
}
console& console::operator<< (unsigned long i) {
sprintf (BUFFER, "%lu", i);
*this << BUFFER;
return *this;
}
console& console::operator<< (float f) {
sprintf (BUFFER, precision, f);
*this << BUFFER;
return *this;
}
console& console::operator<< (double d) {
sprintf (BUFFER, precision, d);
*this << BUFFER;
return *this;
}
console& console::operator<< (char c) {
if (c == '\n') {
//if (suppress == 0) {
cur_line.clr = clr;
add_line (cur_line);
//}
cur_line = mesg ();
} else cur_line.text += c;
return *this;
}
void console::del () {
int len = cmd_line.text.length ();
if (curs_loc > 0 && curs_loc <= len) {
cmd_line.text.erase (cmd_line.text.begin() + curs_loc - 1);
curs_locx = (int) get_char_width (cmd_line.text.substr (0, --curs_loc));
}
}
void console::draw () {
// draw lines
int cx = startx, cy = starty;
int n = 0, i = startl;
line_iterator it = it_startl;
while ((n++ < lines_per_screen) && (i < nlines)) {
const mesg& linei = *it++; i++;
const color& clr = linei.clr;
glColor3f (clr.r, clr.g, clr.b);
draw_string (linei.text, cx, cy);
cy -= line_height;
}
// draw command line
glColor3f (cmd_line.clr.r, cmd_line.clr.g, cmd_line.clr.b);
draw_string (cmd_line.text, cx, cy);
// draw cursor
if (command_mode) {
glColor3f (1, 0, 0);
int px = cx + curs_locx, py = cy - 2;
glBegin (GL_LINES);
glVertex2i (px, py);
glVertex2i (px+char_width, py);
glEnd ();
}
// draw rollup arrow
int py = b_roll.posy;
if (py != cy) b_roll.set_pos (1, cy);
b_roll.draw ();
}
void console::clear () {
lines.clear ();
clear_cmd_line ();
nlines = 0;
startl = 0;
calc_startl_iterator ();
rollup (1);
}
void console::set_window (const box<int>& w) {
win = w;
calc_visual_params ();
}
void console::calc_visual_params () {
char_width = fnt.charwidth.max;
lines_per_screen = (win.top - win.bottom) / line_height - GUTTER;
startx = win.left + 20;
starty = win.top - line_height;
rollup (rollup());
}
extern char get_typed_char ();
int console::handle_input () {
b_roll.handle_input ();
int ret = 0;
static float sc0 = 0.5, sc1 = 1./64;
static float pg0 = 0.5, pg1 = 1./32;
if (keypressed (SDLK_TAB) && !ALT) {
toggle_command_mode ();
return 1;
}
else
if (command_mode) {
if (keypressed (SDLK_ESCAPE)) {
toggle_command_mode ();
return 1;
}
ret = 1;
char c = get_typed_char ();
if (c != 0) {
cmd_line.text.insert (cmd_line.text.begin() + curs_loc++, c);
curs_locx = get_char_width (cmd_line.text.substr (0, curs_loc));
}
if (keypressedd (SDLK_BACKSPACE)) del (); else
if (keypressed (SDLK_RETURN)) {
add_line (cmd_line);
history.push_back (cmd_line.text);
hid = history.size () - 1;
operator() (cmd_line.text);
clear_cmd_line ();
} else if (keypressedd (SDLK_LEFT)) {
if (--curs_loc < 1)
curs_loc = curs_locx = 0;
else
curs_locx = (int) get_char_width (cmd_line.text.substr (0, curs_loc));
} else if (keypressedd (SDLK_RIGHT)) {
int len = cmd_line.text.length ();
if (++curs_loc > len) curs_loc = len;
curs_locx = (int) get_char_width (cmd_line.text.substr (0, curs_loc));
} else if (hid > -1) {
if (keypressedd (SDLK_UP)) {
set_cmd_line (history[hid--]);
if (hid < 0) hid = history.size () - 1;
} else if (keypressedd (SDLK_DOWN)) {
set_cmd_line (history[hid++]);
if (hid >= (int) history.size()) hid = 0;
}
}
return 1;
} else
if (keypressed (SDLK_HOME)) home (); else
if (keypressed (SDLK_END)) end(); else
if (keypressedd (SDLK_PAGEUP, pg0, pg1)) pgup(); else
if (keypressedd (SDLK_PAGEDOWN, pg0, pg1)) pgdn(); else
if (keypressed (SDLK_BACKSPACE)) clear(); else
if (keypressedd (SDLK_UP, sc0, sc1)) up(1); else
if (keypressedd (SDLK_DOWN, sc0, sc1)) down(1);
return ret;
}
void console::rollup (int r) {
rollup_ = r;
if (rollup_ == 1)
b_roll.set_dir (arrow_button::down);
else
b_roll.set_dir (arrow_button::up);
last ();
}
console& console::operator() (const string& cmd) {
into_lines (interpreter(cmd).result, *this);
return *this;
}
void console::set_cmd_line (const string& s, const color& c) {
cmd_line.text = s;
cmd_line.clr = c;
curs_loc = cmd_line.text.length ();
curs_locx = get_char_width (cmd_line.text);
}
void console::clear_cmd_line () {
cmd_line = mesg ();
curs_loc = curs_locx = 0;
}
void console::toggle_command_mode () {
command_mode = !command_mode;
if (command_mode) {
widget::focus = this;
} else widget::focus = 0;
last ();
}
void console::clicked (button& b) {
rollup (!rollup());
if (command_mode) widget::focus = this;
}
console::~console() {
dlog << "--- destroyed console ---" << endl;
}
void console::calc_startl_iterator () {
it_startl = lines.begin ();
for (int i = 0; i < startl; ++i, ++it_startl);
}