/* client/chat.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 "auxiliary/functions.h" #include "core/core.h" #include "client/chat.h" #include "client/console.h" #include "client/keyboard.h" #include "client/video.h" #include "render/render.h" namespace client { namespace chat { // input history std::deque history; std::deque::reverse_iterator history_pos; size_t input_pos = 0; // chatbox visibility bool chat_visible = false; //--- public ------------------------------------------------------ void init() { // add engine functions history.clear(); history.push_back(""); history_pos = history.rbegin(); input_pos = 0; } void shutdown() { history.clear(); input_pos = 0; } bool visible() { return chat_visible; } void draw() { using namespace render; if (console()->visible() || !visible()) return; size_t width = (size_t) (video::width / Text::fontwidth()) - 8; float y = video::height*8/10; Text::draw(4, y, "^BSay^F:^B "); std::string firstpart((*history_pos).substr(0, input_pos)); size_t draw_width = 0; const char *c = firstpart.c_str(); while (*c) { if (aux::is_color_code(c)) { c++; } else { draw_width++; } c++; } c = firstpart.c_str(); while (*c && draw_width > width - 2) { if (aux::is_color_code(c)) { c++; Text::setcolor(*c); } else { draw_width--; } c++; } if (*c) { Text::draw(4+5*Text::fontwidth(), y, c); } if (input_pos < (*history_pos).size()) { // FIXME limit to width if (input_pos > 1 && aux::is_color_code((*history_pos).c_str() + input_pos -1)) { Text::setcolor((*history_pos)[input_pos]); } c = (*history_pos).c_str() + input_pos; Text::draw(4+Text::fontwidth()*(draw_width+5), y, c); } // draw cursor if ((core::application()->time() - ::floorf(core::application()->time())) < 0.5f) { std::string cursor("^B_"); Text::draw(4+Text::fontwidth()*(draw_width+5), y , cursor); } } void toggle() { chat_visible = !chat_visible; if (chat_visible) { input_pos = 0; history_pos = history.rbegin(); (*history_pos).clear(); } setkeyboardmode(console()->visible() || (core::application()->connected() && chat::visible())); } void keypressed(unsigned int key) { std::deque::reverse_iterator upit; switch( key ) { case SDLK_ESCAPE: toggle(); break; case SDLK_TAB: core::CommandBuffer::complete( (*history_pos), input_pos); break; case SDLK_RETURN: if ((*history_pos).size()) { // store input into history while (history.size() >= MAXHISTOLINES) { history.pop_front(); } if ((*history_pos).c_str()[0] == '/' || (*history_pos).c_str()[0] == '\\') { core::cmd() << &(*history_pos).c_str()[1] << std::endl; } else { core::cmd() << "say " << (*history_pos) << std::endl; } (*history.rbegin()) = (*history_pos); history.push_back(""); history_pos = history.rbegin(); input_pos = 0; } toggle(); break; case SDLK_UP: upit = history_pos; ++upit; if (upit != history.rend()) { history_pos = upit; input_pos = (*history_pos).size(); } break; case SDLK_DOWN: if (history_pos != history.rbegin()) { --history_pos; input_pos = (*history_pos).size(); } break; case SDLK_HOME: input_pos = 0; break; case SDLK_END: input_pos = (*history_pos).size(); break; case SDLK_LEFT: if (input_pos > 0) input_pos--; break; case SDLK_RIGHT: if (input_pos < (*history_pos).size()) input_pos++; break; case SDLK_BACKSPACE: if ((*history_pos).size() && input_pos) { (*history_pos).erase(input_pos-1, 1); input_pos--; } break; default: if ((key >= 32 ) && (key <175)) { if (input_pos == (*history_pos).size()) (*history_pos) += (char)key; else (*history_pos).insert(input_pos, 1, (char)key); input_pos++; } break; } } } }