/* client/console.cc This file is part of the Osirion project and is distributed under the terms and conditions of the GNU General Public License version 2 */ #include #include #include #include "auxiliary/functions.h" #include "audio/audio.h" #include "client/chat.h" #include "client/console.h" #include "client/video.h" #include "client/keyboard.h" #include "core/core.h" #include "filesystem/filesystem.h" #include "render/render.h" #include "render/textures.h" namespace client { const float DEFAULT_CONSOLE_HEIGHT = 0.7f; const size_t DEFAULT_MAX_HISTO_LINES = 512; /* -- ConsoleBuffer ------------------------------------------------ */ ConsoleBuffer::ConsoleBuffer() { con_print << "^BInitializing console..." << std::endl; } ConsoleBuffer::~ConsoleBuffer() { con_print << "^BShutting down console..." << std::endl; } // the global console buffer object ConsoleBuffer Console::con_buffer; //--- Console ----------------------------------------------------- Console::Console(ui::Widget *parent) : ui::Window(parent) { set_visible(false); set_border(false); set_background(true); set_label("console"); console_scroll = 0; history.clear(); history.push_back(""); history_pos = history.rbegin(); console_input = new ui::InputBox(this); console_input->set_focus(); console_input->set_border(false); console_input->set_background(false); load_history(); } Console::~Console() { save_history(); history.clear(); } void Console::show() { ui::Window::show(); SDL_WM_GrabInput(SDL_GRAB_OFF); SDL_ShowCursor(SDL_ENABLE); console_scroll = 0; history_pos = history.rbegin(); (*history_pos).clear(); console_input->set_text((*history_pos)); audio::play("ui/console"); } void Console::hide() { ui::Window::hide(); SDL_WM_GrabInput(SDL_GRAB_ON); SDL_ShowCursor(SDL_DISABLE); audio::play("ui/console"); } void Console::toggle() { if (visible()) hide(); else show(); } bool Console::on_keypress(const int key, const unsigned int modifier) { // number of lines to scroll const size_t scroll_offset = 3; Text::reverse_iterator upit; switch( key ) { case SDLK_ESCAPE: if (visible()) { hide(); return true; } else { return false; } break; /* case SDLK_TAB: core::CommandBuffer::complete( (*history_pos), input_pos); return true; break; */ case SDLK_RETURN: if (console_input->text().size()) { // store input in history while (history.size() >= DEFAULT_MAX_HISTO_LINES) { history.pop_front(); } core::cmd() << console_input->text() << std::endl; con_print << "^B>" << console_input->text() << std::endl; (*history.rbegin()).assign(console_input->text()); history.push_back(""); history_pos = history.rbegin(); console_input->set_text((*history_pos)); } return true; break; case SDLK_UP: upit = history_pos; ++upit; if (upit != history.rend()) { history_pos = upit; console_input->set_text((*history_pos)); } return true; break; case SDLK_DOWN: if (history_pos != history.rbegin()) { --history_pos; console_input->set_text((*history_pos)); } return true; break; case SDLK_PAGEUP: console_scroll += scroll_offset; if (console_scroll > log().size()) console_scroll = log().size(); return true; break; case SDLK_PAGEDOWN: if (console_scroll > scroll_offset) console_scroll -= scroll_offset; else console_scroll = 0; return true; break; } return false; } void Console::event_draw() { if (core::application()->connected()) { set_size(parent()->size().width(), parent()->size().height() * DEFAULT_CONSOLE_HEIGHT); } else { set_size(parent()->size()); } ui::Window::event_draw(); } void Console::draw() { console_input->set_size(this->width(), font()->height()); console_input->set_location(0, this->height()-font()->height()); draw_background(); draw_border(); render::Text::setfont(font()->name().c_str(), font()->width(), font()->height()); render::gl::enable(GL_TEXTURE_2D); // draw version below the bottom of the console std::string version(core::name()); version += ' '; version.append(core::version()); render::gl::color(0.0f, 1.0f, 0.0f, 0.5f); render::Text::draw(width()-font()->width()*(version.size()+1), height()-font()->height()-4, version); // draw the console log() if (console_scroll > log().size()) console_scroll = log().size(); int height = (size_t) (this->height() / font()->height()) -1; int width = (size_t) ((this->width()-8) / font()->width()); int bottom = (int) log().size() - console_scroll; int current_line = 0; Text lines; for (Text::iterator it = log().begin(); it != log().end() && current_line < bottom; it++) { if (current_line >= bottom - height) { std::string linedata(*it); linedata += '\n'; std::string word; size_t word_length = 0; std::string line; size_t line_length = 0; const char *c = linedata.c_str(); char pen = 'N'; char wordpen = 'N'; while (*c) { // color code if (aux::is_color_code(c)) { c++; pen = *c; word += '^'; word += pen; } // new word, wrap if necessary else if ((*c == '\n' ) || ( *c == ' ')) { if (line_length + word_length > (size_t) width) { if (line.size()) { lines.push_back(line); line.clear(); line += '^'; line += wordpen; line_length = 0; } } line.append(word); line_length += word_length; word.clear(); word_length = 0; wordpen = pen; // new line if (*c == '\n' ) { lines.push_back(line); line.clear(); line_length = 0; // new word } else if (*c == ' ' ) { line += ' '; line_length++; } } // new character else { word += *c; word_length++; if (word_length == (size_t) width) { if (line.size()) { lines.push_back(line); line.clear(); line += '^'; line += wordpen; line_length = 0; } line.append(word); line_length = word_length; word.clear(); word_length = 0; wordpen = pen; } } c++; } } current_line++; } float y = this->height()-2*font()->height()-4; render::Text::setcolor('N'); for (Text::reverse_iterator rit = lines.rbegin(); (y >= 4) && (rit != lines.rend()); ++rit) { render::Text::draw(4, y, (*rit)); y -= font()->height(); } render::gl::disable(GL_TEXTURE_2D); } void Console::save_history() { if (history.size() <= 1) return; std::string filename(filesystem::writedir()); filename.append("history.txt"); std::ofstream ofs(filename.c_str()); if (!ofs.is_open()) { con_warn << "Could not write " << filename << std::endl; return; } Text::iterator it; size_t l = 1; for (it = history.begin(); it != history.end(); it++) { if (l < history.size()) ofs << (*it) << std::endl; l++; } ofs.close(); } void Console::load_history() { std::string filename(filesystem::writedir()); filename.append("history.txt"); std::ifstream ifs(filename.c_str(), std::ifstream::in); if (!ifs.is_open()) { con_warn << "Could not read " << filename << std::endl; return; } history.clear(); char line[MAXCMDSIZE]; while (ifs.getline(line, MAXCMDSIZE-1)) { history.push_back(line); } ifs.close(); history.push_back(""); history_pos = history.rbegin(); } /* void Console::draw_notify() { // draw notifications size_t width = (size_t) ((width()-8) / font()->width()); size_t n = notify_pos % MAXNOTIFYLINES; float h = height()/2; for (size_t l = 0; l < MAXNOTIFYLINES; l++) { if (notify_text[n].size() > 2 && notify_time[n] + 5 > core::application()->time()) { std::string linedata(notify_text[n]); linedata += '\n'; std::string word; size_t word_length = 0; std::string line; size_t line_length = 0; const char *c = linedata.c_str(); char pen = 'N'; char wordpen = 'N'; render::Text::setcolor('N'); while (*c) { // color code if (aux::is_color_code(c)) { c++; pen = *c; word += '^'; word += pen; } // new word, wrap if necessary else if ((*c == '\n' ) || ( *c == ' ')) { if (line_length + word_length > width) { if (line.size()) { render::Text::draw(4, h, line); h += font()->width(); line.clear(); line += '^'; line += wordpen; line_length = 0; } } line.append(word); line_length += word_length; word.clear(); word_length = 0; wordpen = pen; // new line if (*c == '\n' ) { render::Text::draw(4, h, line); h += font()->width(); line.clear(); line_length = 0; // new word } else if (*c == ' ' ) { line += ' '; line_length++; } } // new character else { word += *c; word_length++; if (word_length == width) { if (line.size()) { render::Text::draw(4, h, line); h += font()->width(); line.clear(); line += '^'; line += wordpen; line_length = 0; } line.append(word); line_length = word_length; word.clear(); word_length = 0; wordpen = pen; } } c++; } } n = (n+1) % MAXNOTIFYLINES; } } void Console::clear_notify() { for (size_t i=0; i < MAXNOTIFYLINES; i++) { notify_text[i].clear(); notify_time[i] = 0; } notify_pos = 0; } void Console::notify(std::string const & message) { // save notification notify_text[notify_pos] = message; notify_time[notify_pos] = core::application()->time(); notify_pos = (notify_pos+1) % MAXNOTIFYLINES; } */ } // namespace client