From 1e0df536c2fae85c317ce9c3cc17603d5f98c911 Mon Sep 17 00:00:00 2001 From: Stijn Buys Date: Wed, 15 Oct 2008 20:33:15 +0000 Subject: moved client console into a Widget --- doc/GAMEPLAY | 10 +- doc/TODO | 4 +- src/client/chat.cc | 9 +- src/client/client.cc | 22 ++- src/client/client.h | 5 + src/client/console.cc | 424 +++++++++++++++++++------------------------- src/client/console.h | 77 ++++---- src/client/input.cc | 69 +------ src/client/view.cc | 17 +- src/core/application.cc | 4 +- src/core/gameserver.cc | 7 +- src/server/console.cc | 63 +++---- src/server/console.h | 13 +- src/server/server.cc | 4 +- src/sys/consoleinterface.cc | 288 ++++++++++++++++-------------- src/sys/consoleinterface.h | 150 +++++++++++----- src/sys/sys.cc | 32 ++-- src/sys/sys.h | 10 +- src/ui/container.cc | 4 +- src/ui/input.cc | 8 +- src/ui/paint.cc | 4 +- src/ui/paint.h | 10 +- src/ui/ui.cc | 37 ++-- src/ui/ui.h | 2 +- src/ui/widget.cc | 14 ++ src/ui/window.cc | 9 +- src/ui/window.h | 5 +- 27 files changed, 649 insertions(+), 652 deletions(-) diff --git a/doc/GAMEPLAY b/doc/GAMEPLAY index 5379654..2f2160b 100644 --- a/doc/GAMEPLAY +++ b/doc/GAMEPLAY @@ -31,11 +31,15 @@ Universe A basic description of the universe, how it is organised and who lives there. The universe is a collection of stand-alone star systems. Each star system - is a small world on it's on. The only direct interaction between systems + is a small world on its on. The only direct interaction between systems is a player traveling between them. The background story should provide (some of the) star systems and their relations. The universe is a static. Players can not intentionally destroyed planets, stations or other objects. + The Project::OSiRiON universe is an open universe. This means players are + free to travel around and visit the places they want, but this does not + mean the player will be welcomed anywhere he goes. + Destructable objects are probably part of a mission, will respawn later or have some other special meaning. @@ -87,7 +91,7 @@ Traveling Neither of these engines will allow the player the leave the star system. Interstellar travel is only possible using a hyperdrive. A hyperdrive is an - expensive piece of equipment that has massive power requirements. Only very + expensive piece of equipment with a massive power requirement. Only very large ships will be capable of carrying a hyperspace jump drive. Interstellar travel for the common men is possible through the use @@ -108,7 +112,7 @@ Traveling Jump gates are built in the vicinity of stable intersection faults and thus have a fixed destination. - Ships equiped with a hyoerdrive work on the same principle. They seek out a sensitive + Ships equiped with a hyperdrive work on the same principle. They seek out a sensitive spot in the hyperspace field and fold local space to punch a hole through the other side. This has several major consequences: a pilot has to determine has destination by finding a good departure point in local space. Also, only a small number of connections between diff --git a/doc/TODO b/doc/TODO index b851d74..b87a3f2 100644 --- a/doc/TODO +++ b/doc/TODO @@ -45,7 +45,7 @@ core: toggle func to toggle a bool cvar (ok) game module loading/unloading (breaks network proto, server must send module type) - zone changes, clear entities + zone changes, clear entities (ok) network: UDP datagrams (ok) @@ -58,7 +58,7 @@ network: round thrust/speed on 1/100 (ok) protocol description (incomplete) - private chat + private chat (ok) zone/system chat (requires zones) group/clan chat (requires groups) rcon authentication, rcon command, servers must be able to disable rcon diff --git a/src/client/chat.cc b/src/client/chat.cc index 87ba437..6d294ba 100644 --- a/src/client/chat.cc +++ b/src/client/chat.cc @@ -6,15 +6,14 @@ #include "auxiliary/functions.h" #include "client/chat.h" -#include "client/client.h" -#include "client/console.h" #include "core/core.h" -#include "render/render.h" #include "sys/sys.h" #include "ui/ui.h" namespace client { +const size_t DEFAULT_MAX_HISTO_LINES = 512; + Chat::Chat(ui::Widget *parent) : ui::Window(parent) { set_label("chat"); @@ -83,7 +82,7 @@ bool Chat::on_keypress(const int key, const unsigned int modifier) (*history_pos).assign(chat_input->text()); // store input into history - while (history.size() >= MAXHISTOLINES) { + while (history.size() >= DEFAULT_MAX_HISTO_LINES) { history.pop_front(); } @@ -127,7 +126,7 @@ bool Chat::on_keypress(const int key, const unsigned int modifier) void Chat::event_draw() { - if (!client()->connected()) { + if (!core::application()->connected()) { hide(); return; } diff --git a/src/client/client.cc b/src/client/client.cc index ae4f232..200becd 100644 --- a/src/client/client.cc +++ b/src/client/client.cc @@ -58,6 +58,11 @@ void func_ui_chat(std::string const &args) } } +void func_ui_console(std::string const &args) +{ + client()->console()->toggle(); +} + //--- public ------------------------------------------------------ void client_main(int count, char **arguments) @@ -93,7 +98,6 @@ void Client::init(int count, char **arguments) // initialize core core::Cvar::sv_dedicated = core::Cvar::set("sv_private", "0"); core::Application::init(count, arguments); - Console::init(); // client variables core::Cvar *cvar = 0; @@ -114,7 +118,9 @@ void Client::init(int count, char **arguments) // initialize user interface ui::init(); + client_view = new View(ui::root()); + client_console = new Console(ui::root()); // Initialize the video subsystem if (!video::init()) { @@ -136,6 +142,9 @@ void Client::init(int count, char **arguments) func = core::Func::add("ui_chat", func_ui_chat); func->set_info("toggle chat window"); + func = core::Func::add("ui_console", func_ui_console); + func->set_info("toggle console on or off"); + //func = core::Func::add("snd_restart", (core::FuncPtr) func_snd_restart); //func->set_info("restart audio subsystem"); } @@ -149,10 +158,8 @@ void Client::run() Uint32 client_current_timestamp = 0; Uint32 client_previous_timestamp = 0; - - - console()->flush(); - console()->clear_notify(); + + //console()->clear_notify(); while (true) { // current time in microseconds @@ -222,12 +229,11 @@ void Client::shutdown() core::Func::remove("r_restart"); core::Func::remove("ui_chat"); + core::Func::remove("ui_console"); //core::Func::remove("snd_restart"); audio::shutdown(); - Console::shutdown(); - input::shutdown(); video::shutdown(); @@ -290,7 +296,7 @@ void Client::notify_message(core::Message::Channel const channel, std::string co } con_print << message << std::endl; - console()->notify(message); + //console()->notify(message); } /* FIXME diff --git a/src/client/client.h b/src/client/client.h index dc70e16..6e19848 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -8,6 +8,7 @@ #define __INCLUDED_CLIENT_H__ #include "core/application.h" +#include "client/console.h" #include "client/view.h" /// client part of the engine @@ -50,12 +51,16 @@ public: /// the main client view inline View *view() { return client_view; } + /// the client console + inline Console *console() { return client_console; } + protected: /// run a client frame virtual void frame(float seconds); private: View *client_view; + Console *client_console; }; diff --git a/src/client/console.cc b/src/client/console.cc index 47f95f7..0ab0767 100644 --- a/src/client/console.cc +++ b/src/client/console.cc @@ -21,97 +21,112 @@ namespace client { -Console client_console; +const float DEFAULT_CONSOLE_HEIGHT = 0.7f; +const size_t DEFAULT_MAX_HISTO_LINES = 512; -Console *console() { - return &client_console; -} - -//--- public ------------------------------------------------------ - -void Console::init() +/* -- ConsoleBuffer ------------------------------------------------ */ +ConsoleBuffer::ConsoleBuffer() { con_print << "^BInitializing console..." << std::endl; - console()->load_history(); + } -void Console::shutdown() +ConsoleBuffer::~ConsoleBuffer() { con_print << "^BShutting down console..." << std::endl; - console()->save_history(); } +// the global console buffer object +ConsoleBuffer Console::con_buffer; + //--- Console ----------------------------------------------------- -Console::Console() +Console::Console(ui::Widget *parent) : ui::Window(parent) { - clear(); -} + set_visible(false); + set_border(false); + set_background(true); + set_label("console"); -Console::~Console() -{ - history.clear(); -} + //clear_notify(); + load_history(); -void Console::clear() -{ - console_visible = false; - console_scroll = 0; + console_scroll = 0; history.clear(); history.push_back(""); history_pos = history.rbegin(); - input_pos = 0; - - clear_notify(); + console_input = new ui::Input(this); + console_input->set_focus(); + console_input->set_border(false); + console_input->set_background(false); } -void Console::draw(bool draw_ui_notifications) { - flush(); - if (visible()) - draw_console(); - else if (draw_ui_notifications) - draw_notify(); +Console::~Console() +{ + save_history(); + history.clear(); } -void Console::toggle() +void Console::show() { - console_visible = !console_visible; - - if (console_visible) { - console_scroll = 0; - input_pos = 0; + ui::Window::show(); + SDL_WM_GrabInput(SDL_GRAB_OFF); + SDL_ShowCursor(SDL_ENABLE); - history_pos = history.rbegin(); - (*history_pos).clear(); + console_scroll = 0; + history_pos = history.rbegin(); + (*history_pos).clear(); + console_input->set_text((*history_pos)); - SDL_WM_GrabInput(SDL_GRAB_OFF); - SDL_ShowCursor(SDL_ENABLE); - } else { - SDL_WM_GrabInput(SDL_GRAB_ON); - SDL_ShowCursor(SDL_DISABLE); - } + audio::play("ui/console"); +} - //setkeyboardmode(console()->visible() || (core::application()->connected() && chat::visible())); +void Console::hide() +{ + ui::Window::hide(); + SDL_WM_GrabInput(SDL_GRAB_ON); + SDL_ShowCursor(SDL_DISABLE); audio::play("ui/console"); } -void Console::keypressed(unsigned int key) +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; - std::deque::reverse_iterator upit; + 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 ((*history_pos).size()) { - // store input into history - while (history.size() >= MAXHISTOLINES) { + if (console_input->text().size()) { + // store input in history + (*history_pos).assign(console_input->text()); + while (history.size() >= DEFAULT_MAX_HISTO_LINES) { history.pop_front(); } @@ -121,132 +136,88 @@ void Console::keypressed(unsigned int key) history.push_back(""); history_pos = history.rbegin(); - input_pos = 0; + console_input->set_text((*history_pos)); } + return true; break; + case SDLK_UP: upit = history_pos; ++upit; if (upit != history.rend()) { history_pos = upit; - input_pos = (*history_pos).size(); + console_input->set_text((*history_pos)); } + return true; 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_DELETE: - if ((*history_pos).size() && input_pos < (*history_pos).size()) { - (*history_pos).erase(input_pos, 1); - } - break; - case SDLK_BACKSPACE: - if ((*history_pos).size() && input_pos) { - (*history_pos).erase(input_pos-1, 1); - input_pos--; + console_input->set_text((*history_pos)); } + return true; break; case SDLK_PAGEUP: console_scroll += scroll_offset; - if (console_scroll > consoleinterface_text.size()) - console_scroll = consoleinterface_text.size(); + 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; - break; - default: - if ((key >= 32 ) && (key <175) && ((*history_pos).size() < MAXCMDSIZE)) { - if (input_pos == (*history_pos).size()) - (*history_pos) += (char)key; - else - (*history_pos).insert(input_pos, 1, (char)key); - input_pos++; - } + return true; break; } - + return false; } -void Console::save_history() +void Console::event_draw() { - 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; - } - std::deque::iterator it; - size_t l = 1; - for (it = history.begin(); it != history.end(); it++) { - if (l < history.size()) - ofs << (*it) << std::endl; - l++; + if (core::application()->connected()) { + set_size(parent()->size().width(), parent()->size().height() * DEFAULT_CONSOLE_HEIGHT); + } else { + set_size(parent()->size()); } - ofs.close(); + ui::Window::event_draw(); } -void Console::load_history() +void Console::draw() { - 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; - } + console_input->set_size(this->width(), font()->height()); + console_input->set_location(0, this->height()-font()->height()); - history.clear(); - char line[MAXCMDSIZE]; - while (ifs.getline(line, MAXCMDSIZE-1)) { - history.push_back(line); - } + draw_background(); + draw_border(); - ifs.close(); + render::Text::setfont(font()->name().c_str(), font()->width(), font()->height()); + render::gl::enable(GL_TEXTURE_2D); - history.push_back(""); - history_pos = history.rbegin(); - input_pos = 0; -} + // 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); -void Console::draw_notify() -{ - using namespace render; + // draw the console log() + if (console_scroll > log().size()) + console_scroll = log().size(); + + size_t height = (size_t) (this->height() / font()->height()) -1; + size_t width = (size_t) ((this->width()-8) / font()->width()); + size_t bottom = log().size() - console_scroll; + size_t current_line = 0; - // draw notifications - size_t width = (size_t) ((video::width-8) / Text::fontwidth()); - size_t n = notify_pos % MAXNOTIFYLINES; - float h = video::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]); + 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; @@ -258,7 +229,6 @@ void Console::draw_notify() const char *c = linedata.c_str(); char pen = 'N'; char wordpen = 'N'; - Text::setcolor('N'); while (*c) { @@ -275,8 +245,7 @@ void Console::draw_notify() if (line_length + word_length > width) { if (line.size()) { - Text::draw(4, h, line); - h += Text::fontheight(); + lines.push_back(line); line.clear(); line += '^'; line += wordpen; @@ -293,8 +262,7 @@ void Console::draw_notify() // new line if (*c == '\n' ) { - Text::draw(4, h, line); - h += Text::fontheight(); + lines.push_back(line); line.clear(); line_length = 0; // new word @@ -311,8 +279,7 @@ void Console::draw_notify() if (word_length == width) { if (line.size()) { - Text::draw(4, h, line); - h += Text::fontheight(); + lines.push_back(line); line.clear(); line += '^'; line += wordpen; @@ -332,49 +299,78 @@ void Console::draw_notify() } } - n = (n+1) % MAXNOTIFYLINES; + 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::draw_console() +void Console::save_history() { - using namespace render; + if (history.size() <= 1) + return; - float con_height = 0.70f; - - gl::disable(GL_TEXTURE_2D); + std::string filename(filesystem::writedir()); + filename.append("history.txt"); + std::ofstream ofs(filename.c_str()); - // draw the transparent console background - gl::color(0.0f, 0.0f, 0.0f, 0.5f); - gl::begin(gl::Quads); - gl::vertex(0.0f, 0.0f, 0.0f); - gl::vertex(video::width, 0.0f,0.0f); - gl::vertex(video::width,video::height*con_height,0.0f); - gl::vertex(0,video::height*con_height,0.0f); - gl::end(); + 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++; + } - gl::enable(GL_TEXTURE_2D); + ofs.close(); +} - // draw version below the bottom of the console - std::string version(core::name()); - version += ' '; - version.append(core::version()); - gl::color(0.0f, 1.0f, 0.0f, 0.5f); - Text::draw(video::width-Text::fontwidth()*(version.size()+1), video::height*con_height-Text::fontheight()-4, version); +void Console::load_history() +{ + std::string filename(filesystem::writedir()); + filename.append("history.txt"); + std::ifstream ifs(filename.c_str(), std::ifstream::in); - // draw the console consoleinterface_text - if (console_scroll > consoleinterface_text.size()) - console_scroll = consoleinterface_text.size(); - - size_t height = (size_t) (video::height * con_height / Text::fontheight()) -1; - size_t width = (size_t) ((video::width-8) / Text::fontwidth()); - size_t bottom = consoleinterface_text.size() - console_scroll; - size_t current_line = 0; + if (!ifs.is_open()) { + con_warn << "Could not read " << filename << std::endl; + return; + } - std::deque lines; - for (std::deque::iterator it = consoleinterface_text.begin(); it != consoleinterface_text.end() && current_line < bottom; it++) { - if (current_line >= bottom - height) { - std::string linedata(*it); + 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; @@ -386,6 +382,7 @@ void Console::draw_console() const char *c = linedata.c_str(); char pen = 'N'; char wordpen = 'N'; + render::Text::setcolor('N'); while (*c) { @@ -402,7 +399,8 @@ void Console::draw_console() if (line_length + word_length > width) { if (line.size()) { - lines.push_back(line); + render::Text::draw(4, h, line); + h += font()->width(); line.clear(); line += '^'; line += wordpen; @@ -419,7 +417,8 @@ void Console::draw_console() // new line if (*c == '\n' ) { - lines.push_back(line); + render::Text::draw(4, h, line); + h += font()->width(); line.clear(); line_length = 0; // new word @@ -436,7 +435,8 @@ void Console::draw_console() if (word_length == width) { if (line.size()) { - lines.push_back(line); + render::Text::draw(4, h, line); + h += font()->width(); line.clear(); line += '^'; line += wordpen; @@ -456,65 +456,8 @@ void Console::draw_console() } } - current_line++; - } - - float y = video::height*con_height-2*Text::fontheight()-4; - Text::setcolor('N'); - for (std::deque::reverse_iterator rit = lines.rbegin(); (y >= 4) && (rit != lines.rend()); ++rit) { - Text::draw(4, y, (*rit)); - y -= Text::fontheight(); - } - - - // draw the console input - y = video::height*con_height - Text::fontheight() - 4; - Text::draw(4, y, "^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+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+1), y, c); - } - - // draw cursor - if ((core::application()->time() - ::floorf(core::application()->time())) < 0.5f) { - std::string cursor("^B"); - cursor += (char) 11; - Text::draw(4+Text::fontwidth()*(draw_width+1), y , cursor); + n = (n+1) % MAXNOTIFYLINES; } - } @@ -534,6 +477,7 @@ void Console::notify(std::string const & message) notify_time[notify_pos] = core::application()->time(); notify_pos = (notify_pos+1) % MAXNOTIFYLINES; } +*/ } // namespace client diff --git a/src/client/console.h b/src/client/console.h index e280e9d..4b2df20 100644 --- a/src/client/console.h +++ b/src/client/console.h @@ -8,35 +8,31 @@ #define __INCLUDED_CLIENT_CONSOLE_H__ #include "sys/consoleinterface.h" +#include "ui/window.h" +#include "ui/input.h" namespace client { -const size_t MAXNOTIFYLINES = 5; -const size_t MAXHISTOLINES = 512; +/* -- class ConsoleBuffer ------------------------------------------ */ -/// client console implementation -class Console : public sys::ConsoleInterface { +/// client console buffer +/** stores incoming console messages + */ +class ConsoleBuffer : public sys::ConsoleInterface { public: - Console(); - virtual ~Console(); - - /// add notification - void notify(std::string const &message); - - /// clear notifications - void clear_notify(); - - /// draw client notifications or console text - void draw(bool draw_ui_notifications); + ConsoleBuffer(); + ~ConsoleBuffer(); +}; - /// toggle the console on or off - void toggle(); +/* -- class Console ------------------------------------------------ */ - /// handle keyboard input - void keypressed(unsigned int key); +/// client system console widget +class Console : public ui::Window { +public: + typedef std::deque Text; - /// true of the console is visible - inline bool visible() { return console_visible; } + Console(Widget *parent); + virtual ~Console(); /// load input history void load_history(); @@ -44,37 +40,40 @@ public: /// save input history void save_history(); - /// clear console - void clear(); + /// show console + virtual void show(); - /// initialize client console - static void init(); + /// hide console + virtual void hide(); - /// shutdown the client console - static void shutdown(); + void toggle(); protected: - void draw_console(); + /// draw event + virtual void event_draw(); - void draw_notify(); + /// draw the client console text + virtual void draw(); + + /// handle keypress events + virtual bool on_keypress(const int key, const unsigned int modifier); private: - // notifications - size_t notify_pos; - std::string notify_text[MAXNOTIFYLINES]; - float notify_time[MAXNOTIFYLINES]; + inline Text & log() { return con_buffer.log(); } // input history - std::deque history; - std::deque::reverse_iterator history_pos; - size_t input_pos; + Text history; + Text::reverse_iterator history_pos; - bool console_visible; + // scroll position size_t console_scroll; -}; + // input widget + ui::Input *console_input; -Console *console(); + // console buffer + static ConsoleBuffer con_buffer; +}; } diff --git a/src/client/input.cc b/src/client/input.cc index 22fd1c0..a72999e 100644 --- a/src/client/input.cc +++ b/src/client/input.cc @@ -133,11 +133,6 @@ void func_ui_control(std::string const &args) audio::play("ui/control"); } -void func_ui_console(std::string const &args) -{ - console()->toggle(); -} - void func_view_next(std::string const &args) { if (core::application()->connected() && core::localcontrol()) { @@ -268,12 +263,6 @@ void init() input_mousedelay->set_info("[int] mouse click time-out in milliseconds"); core::Func *func = 0; - func = core::Func::add("ui_console", func_ui_console); - func->set_info("toggle console on or off"); - - //func = core::Func::add("ui_chat", func_ui_chat); - //func->set_info("toggle chatbox on or of"); - func = core::Func::add("ui_control",func_ui_control); func->set_info("toggle mouse control"); @@ -323,9 +312,7 @@ void shutdown() core::Func::remove("screenshot"); - core::Func::remove("ui_console"); - //core::Func::remove("ui_control"); - //core::Func::remove("ui_chat"); + core::Func::remove("ui_control"); core::Func::remove("ui_view"); keyboard->save_binds(); @@ -489,38 +476,8 @@ Key::Modifier convert_SDL_modifier(int const sdlmodifier) void key_pressed(Key *key) { - ui::root()->input_key(true, Keyboard::translate_keysym(key->sym(), keyboard_modifiers), keyboard_modifiers); - - if (key->sym() == SDLK_ESCAPE) { - - if (console()->visible()) { - console()->toggle(); - local_direction = 0.0f; - local_pitch = 0.0f; - local_roll = 0.0f; - - render::Camera::set_direction(0.0f); - render::Camera::set_pitch(0.0f); - - } else { - if (ui::root()->active()) { - ui::root()->hide_menu(); - local_direction = 0.0f; - local_pitch = 0.0f; - local_roll = 0.0f; - - render::Camera::set_direction(0.0f); - render::Camera::set_pitch(0.0f); - } else { - if (core::application()->connected()) { - ui::root()->show_menu("game"); - } else { - ui::root()->show_menu("main"); - } - } - } - - } else if (key->bind(Key::None).compare("ui_console") == 0) { + if (key->bind(Key::None).compare("ui_console") == 0) { + // FIXME bah local_direction = 0.0f; local_pitch = 0.0f; local_roll = 0.0f; @@ -528,21 +485,11 @@ void key_pressed(Key *key) render::Camera::set_direction(0.0f); render::Camera::set_pitch(0.0f); - console()->toggle(); + client()->console()->toggle(); - } else if (console()->visible()) { - // send key events to the console - if (key->sym() < 512) - console()->keypressed(Keyboard::translate_keysym(key->sym(), keyboard_modifiers)); + } else if (ui::root()->input_key(true, Keyboard::translate_keysym(key->sym(), keyboard_modifiers), keyboard_modifiers)) { + return; - } else if (ui::root()->active()) { -/* ui::root()->input_key(true, key->sym(), keyboard_modifiers); -*/ -/* } else if (chat::visible()) { - // send key events to the chat box - if (key->sym() < 512) - chat::keypressed(translate_keysym(key->sym(), keyboard_modifiers)); -*/ } else if (core::application()->connected() && core::localcontrol()) { char c = key->bind(convert_SDL_modifier(keyboard_modifiers)).c_str()[0]; @@ -553,6 +500,7 @@ void key_pressed(Key *key) // normal bind core::cmd() << key->bind(convert_SDL_modifier(keyboard_modifiers)) << "\n"; } + } else if (core::application()->connected()) { char c = key->bind(convert_SDL_modifier(keyboard_modifiers)).c_str()[0]; @@ -561,7 +509,6 @@ void key_pressed(Key *key) core::cmd() << key->bind(convert_SDL_modifier(keyboard_modifiers)) << "\n"; } } - } void key_released(Key *key) @@ -813,7 +760,7 @@ void frame(float seconds) mouse_deadzone = false; if (core::application()->connected() && core::localcontrol()) { - mouse_control = !console()->visible() && ((input_mousecontrol->value() > 0) || (mouse_control_override && (mouse_control_override_time + (input_mousedelay->value() / 1000.0f) < core::application()->time()))); + mouse_control = client()->console()->hidden() && !ui::root()->active() && ((input_mousecontrol->value() > 0) || (mouse_control_override && (mouse_control_override_time + (input_mousedelay->value() / 1000.0f) < core::application()->time()))); if (mouse_control && joystick_control && ((render::Camera::mode() == render::Camera::Track) || (render::Camera::mode() == render::Camera::Cockpit))) { if (!(mouse_control_override && (mouse_control_override_time + (input_mousedelay->value() / 1000.0f) < core::application()->time()))) { diff --git a/src/client/view.cc b/src/client/view.cc index 463d254..a8d9c4f 100644 --- a/src/client/view.cc +++ b/src/client/view.cc @@ -243,12 +243,6 @@ void View::draw() } else { view_center->set_visible(false); } - - if (!ui::root()->active() && !has_input_focus()) { - set_focus(); - } - - } /* -- namespace view ----------------------------------------------- */ @@ -628,7 +622,7 @@ void draw_hud() void draw_cursor() { - if (console()->visible()) + if (client()->console()->visible()) return; float angle = 0; @@ -731,9 +725,6 @@ void frame(float elapsed) { using namespace render; - // flush console messages - console()->flush(); - // Clear the color and depth buffers. gl::clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -778,11 +769,7 @@ void frame(float elapsed) draw_cursor(); } - // draw console or notifications - Text::setfont("gui", 12, 18); - - console()->draw((bool) draw_ui->value()); - + gl::disable(GL_TEXTURE_2D); gl::disable(GL_BLEND); } diff --git a/src/core/application.cc b/src/core/application.cc index db4f338..f98d44e 100644 --- a/src/core/application.cc +++ b/src/core/application.cc @@ -230,7 +230,7 @@ void Application::init(int count, char **arguments) Cvar::con_ansi = Cvar::get("con_ansi", "1", Cvar::Archive); #endif Cvar::con_ansi->set_info("[bool] console ANSI colors"); - sys::ConsoleInterface::instance()->set_ansi(Cvar::con_ansi->value()); + sys::set_ansi(Cvar::con_ansi->value()); #ifdef _WIN32 // Initialize win32 socket library @@ -302,8 +302,6 @@ void Application::shutdown() void Application::quit(int status) { - console()->flush(); - sys::quit(status); } diff --git a/src/core/gameserver.cc b/src/core/gameserver.cc index 46c3624..e42d1b2 100644 --- a/src/core/gameserver.cc +++ b/src/core/gameserver.cc @@ -484,7 +484,6 @@ void GameServer::exec(Player *player, std::string const & cmdline) Func *function = Func::find(command); if (function ) { - std::string args; if (cmdline.size() > command.size() +1 ) args.assign(cmdline.substr(command.size()+1)); @@ -499,9 +498,9 @@ void GameServer::exec(Player *player, std::string const & cmdline) console()->set_rcon(true); function->exec(args); - char line[MAXCMDSIZE]; - while(console()->buffer().getline(line, MAXCMDSIZE-1)) { - send(player, std::string(line)); + while(console()->rconbuf().size()) { + send(player, (*console()->rconbuf().begin())); + console()->rconbuf().pop_front(); } // disable rcon buffering diff --git a/src/server/console.cc b/src/server/console.cc index 3f32337..ab03c58 100644 --- a/src/server/console.cc +++ b/src/server/console.cc @@ -59,14 +59,15 @@ void Console::init() init_pair(4, COLOR_BLUE, -1); init_pair(5, COLOR_CYAN, -1); init_pair(6, COLOR_MAGENTA, -1); - init_pair(7, -1, -1); + init_pair(7, COLOR_WHITE, -1); + init_pair(8, -1, -1); } console_initialized = true; console_updated = true; #endif // HAVE_CURSES - con_print << "Initializing console..." << std::endl; + con_print << "^BInitializing console..." << std::endl; #ifdef HAVE_CURSES server_console.history.clear(); @@ -80,7 +81,7 @@ void Console::init() void Console::shutdown() { - con_print << "Shutting down console..." << std::endl; + con_print << "^BShutting down console..." << std::endl; #ifdef HAVE_CURSES server_console.draw(); @@ -91,15 +92,20 @@ void Console::shutdown() #endif } +Console::Console() +{ +} + +Console::~Console() +{ +} + #ifdef HAVE_CURSES void Console::dump() { - flush(); - // dump console content - for (std::deque::iterator it = consoleinterface_text.begin(); it != consoleinterface_text.end(); it++) { - print_ansi((*it).c_str()); - std::cout << std::endl; + for (Text::iterator it = log().begin(); it != log().end(); it++) { + sys::ConsoleInterface::print((*it)); } } @@ -114,23 +120,9 @@ void Console::resize() draw(); } -void Console::flush() +void Console::print(const std::string & text) { - if (rcon()) - return; - - char line[MAXCMDSIZE]; - - while(consoleinterface_buffer.getline(line, MAXCMDSIZE-1)) { - - while (consoleinterface_text.size() >= sys::MAXCONLINES) { - consoleinterface_text.pop_front(); - } - consoleinterface_text.push_back(std::string(line)); - console_updated = true; - } - - consoleinterface_buffer.clear(); + console_updated = true; } void Console::set_color(const char *color_code) @@ -143,10 +135,10 @@ void Console::set_color(const char *color_code) if (aux::is_base_color_code(color_code)) { // base colors - // Black=0, Red=1, Green=2, Yellow=3, Blue=4, Cyan=5, Magenta=6, White=7 + // Default=0, Red=1, Green=2, Yellow=3, Blue=4, Cyan=5, Magenta=6, White=7 color = *(color_code+1) - '0'; - if (color == 3 || color == 0) + if (color == 3 || color == 7) bold = true; else bold = false; @@ -223,15 +215,15 @@ void Console::draw_text() if ((w < 3) || (h < 3)) return; - std::deque lines; + Text lines; int height = stdwin->_maxy - 1; int width = stdwin->_maxx - 1; - int bottom = (int) consoleinterface_text.size() - console_scroll; + int bottom = (int) log().size() - console_scroll; int current_line = 0; // parse console text, wrap long lines - for (std::deque::iterator it = consoleinterface_text.begin(); it != consoleinterface_text.end() && current_line < bottom; it++) { + for (Text::iterator it = log().begin(); it != log().end() && current_line < bottom; it++) { if (current_line >= bottom - height) { std::string linedata(*it); linedata += '\n'; @@ -322,7 +314,7 @@ void Console::draw_text() color_set(0, NULL); attroff(A_BOLD); - for (std::deque::reverse_iterator rit = lines.rbegin(); (y > 0) && (rit != lines.rend()); ++rit) { + for (Text::reverse_iterator rit = lines.rbegin(); (y > 0) && (rit != lines.rend()); ++rit) { const char *c = (*rit).c_str(); int x = 0; @@ -366,20 +358,16 @@ void Console::draw() wrefresh(stdwin); console_updated = false; - console_lastrefresh = 0; } void Console::frame(float seconds) { const size_t scroll_offset = 3; - std::deque::reverse_iterator upit; - - flush(); + Text::reverse_iterator upit; if (!console_initialized) return; - console_lastrefresh += seconds; bool input_updated = false; int key = wgetch(stdwin); @@ -450,8 +438,8 @@ void Console::frame(float seconds) break; } else if (key == KEY_PPAGE) { console_scroll += scroll_offset; - if (console_scroll > consoleinterface_text.size()) - console_scroll = consoleinterface_text.size(); + if (console_scroll > log().size()) + console_scroll = log().size(); console_updated = true; break; } else if (key == KEY_NPAGE) { @@ -487,6 +475,7 @@ void Console::frame(float seconds) if (input_updated) { // move the cursor to input position move(stdwin->_maxy, 1 + input_pos); + wrefresh(stdwin); } } } diff --git a/src/server/console.h b/src/server/console.h index bf77ecd..59d65d9 100644 --- a/src/server/console.h +++ b/src/server/console.h @@ -13,14 +13,15 @@ namespace server { class Console : public sys::ConsoleInterface { public: + Console(); + ~Console(); + /// initialize the server console static void init(); /// shutdown the server console static void shutdown(); #ifdef HAVE_CURSES - /// flush buffered messages - virtual void flush(); /// resize the console virtual void resize(); /// run one console frame @@ -39,16 +40,16 @@ protected: void draw_input(); /// dump console content to cout void dump(); + /// print one line of text (do nothing) + virtual void print(const std::string & text); private: /// set ncurses drawing color void set_color(const char *color_code); - /// timestamp for screen refresh timeout - float console_lastrefresh; // input history - std::deque history; - std::deque::reverse_iterator history_pos; + Text history; + Text::reverse_iterator history_pos; size_t input_pos; size_t console_scroll; diff --git a/src/server/server.cc b/src/server/server.cc index 27cf6bd..f08ca6c 100644 --- a/src/server/server.cc +++ b/src/server/server.cc @@ -56,7 +56,7 @@ void main(int count, char **arguments) void Server::init(int count, char **arguments) { - con_print << "Initializing server..." << std::endl; + con_print << "^BInitializing server..." << std::endl; core::Cvar::sv_private = core::Cvar::set("sv_dedicated", "1", core::Cvar::ReadOnly); core::Application::init(count, arguments); @@ -92,7 +92,7 @@ void Server::run() void Server::shutdown() { - con_print << "Shutting down server..." << std::endl; + con_print << "^BShutting down server..." << std::endl; float ratio = 0; if (core::Stats::network_uncompressed_bytes_sent > 0) diff --git a/src/sys/consoleinterface.cc b/src/sys/consoleinterface.cc index 073f34b..284a48d 100644 --- a/src/sys/consoleinterface.cc +++ b/src/sys/consoleinterface.cc @@ -6,187 +6,213 @@ #include "sys/consoleinterface.h" -#include - -#include - namespace sys { -ConsoleInterface *ConsoleInterface::consoleinterface_instance = 0; - -ConsoleInterface::ConsoleInterface() -{ - consoleinterface_ansi = true; - if (consoleinterface_instance) { - std::cerr << "multiple sys::ConsoleInterface instances!" << std::endl; - sys::quit(2); - } - - consoleinterface_rcon = false; - - consoleinterface_instance = this; - consoleinterface_text.clear(); - consoleinterface_buffer.clear(); -} - -ConsoleInterface::~ConsoleInterface() -{ - consoleinterface_instance = 0; -} - -ConsoleInterface *ConsoleInterface::instance() -{ - return consoleinterface_instance; -} - -std::ostream & ConsoleInterface::messagestream() -{ - flush(); - return (consoleinterface_buffer << "^N"); -} +const size_t DEFAULT_LOGSIZE = 2048; -std::ostream & ConsoleInterface::warningstream() -{ - flush(); - return (consoleinterface_buffer << "^W"); -} +/* -- ANSI color code support -------------------------------------- */ -std::ostream & ConsoleInterface::errorstream() -{ - flush(); - return (consoleinterface_buffer << "^R"); -} +bool con_ansicolor = false; -std::ostream & ConsoleInterface::debugstream() +bool ansi() { - flush(); - return (consoleinterface_buffer << "^D"); + return con_ansicolor; } -void ConsoleInterface::flush() +void set_ansi(const bool ansi) { - if (rcon()) - return; - - char line[MAXCMDSIZE]; - - while(consoleinterface_buffer.getline(line, MAXCMDSIZE-1)) { - while (consoleinterface_text.size() >= MAXCONLINES) { - consoleinterface_text.pop_front(); - } - consoleinterface_text.push_back(std::string(line)); - - // print to stdout - print_ansi(line); - std::cout << std::endl; + con_ansicolor = ansi; + if (con_ansicolor) { + // ANSI default color + std::cout << "\033[0;39m"; } - - consoleinterface_buffer.clear(); -} - -void ConsoleInterface::resize() -{ } -void ConsoleInterface::print_ansi(const char *line) +void fallback_print(const std::string &text) { - if (consoleinterface_ansi) - std::cout << "\033[0;39m"; - - const char *c = line; + bool is_color_code = false; + int ansi_bold = 0; + int ansi_color = 39; + + const char *c = text.c_str(); while (*c) { + + if ((*c) == '\n') { + std::cout << std::endl; + + } else if ((*c) == '^') { - if ((*c == '^')) { - bool is_code = true; - int bold = 0; - int color = 39; - + is_color_code = true; + ansi_bold = 0; + ansi_color = 39; + switch (*(c+1)) { case '0': // black - color = 0; - bold = 1; - break; - case '1': // red - color = 31; - break; - case '2': // green - color = 32; - break; - case '3': // yellow - bold = 1; - color = 33; - break; - case '4': // blue - color = 34; - break; - case '5': // cyan - color = 36; - break; - case '6': // magenta - color = 35; - break; - case '7': // white is mapped to foreground color - bold = 1; - color = 39; + ansi_color = 0; + ansi_bold = 1; break; - + case '1': // red + ansi_color = 31; + break; + case '2': // green + ansi_color = 32; + break; + case '3': // yellow + ansi_color = 1; + ansi_color = 33; + break; + case '4': // blue + ansi_color = 34; + break; + case '5': // cyan + ansi_color = 36; + break; + case '6': // magenta + ansi_color = 35; + break; + case '7': // white is mapped to foreground color + ansi_bold = 1; + ansi_color = 39; + break; + case 'N': // normal - bold = 0; - color = 39; + ansi_bold = 0; + ansi_color = 39; break; case 'B': // bold - bold = 1; - color = 39; + ansi_bold = 1; + ansi_color = 39; break; case 'D': // debug - bold = 0; - color = 39; + ansi_bold = 0; + ansi_color = 39; break; case 'R': // error - bold = 0; - color = 31; + ansi_bold = 0; + ansi_color = 31; break; case 'W': // warning - bold = 1; - color = 33; + ansi_bold = 1; + ansi_color = 33; break; case 'F': // fancy - bold = 0; - color = 32; + ansi_bold = 0; + ansi_color = 32; break; default: - is_code = false; + is_color_code = false; } - if (is_code) { + + if (is_color_code) { + if (con_ansicolor) + std::cout << "\033[" << ansi_bold << ";" << ansi_color << "m"; c++; - if (consoleinterface_ansi) - std::cout << "\033[" << bold << ";" << color << "m"; - } else + } else { std::cout << *c; + } + } else { std::cout << *c; } + c++; } +} - if (consoleinterface_ansi) - std::cout << "\033[0;39m"; +/* -- ConsoleBuffer ------------------------------------------------ */ + +int ConsoleBuffer::overflow(int c) +{ + if (c == Traits::eof()) + return Traits::not_eof(c); + + if (c == '\n') { + if (ConsoleInterface::instance()) { + ConsoleInterface::instance()->event_text(con_buffer); + } else { + fallback_print(con_buffer); + std::cout << std::endl; + } + con_buffer.clear(); + } else { + con_buffer += c; + } + return c; } -void ConsoleInterface::set_ansi(bool enable) +/* -- ConsoleStream ------------------------------------------------ */ + +ConsoleStream con_out; + +ConsoleStream::ConsoleStream() : std::basic_ostream(&con_buffer) { - consoleinterface_ansi = enable; + clear(); } -void ConsoleInterface::set_rcon(bool enable) +ConsoleStream::~ConsoleStream() { - if (enable) { - flush(); + if (con_ansicolor) { + // ANSI default color + std::cout << "\033[0;39m" << std::endl; } +} + +/* -- Console ------------------------------------------------------ */ + +ConsoleInterface *ConsoleInterface::consoleinterface_instance = 0; + +ConsoleInterface::ConsoleInterface() +{ + if (consoleinterface_instance) { + std::cerr << "multiple sys::ConsoleInterface instances!" << std::endl; + sys::quit(2); + } + + consoleinterface_rcon = false; + consoleinterface_instance = this; + consoleinterface_logsize = DEFAULT_LOGSIZE; +} + +ConsoleInterface::~ConsoleInterface() +{ + consoleinterface_instance = 0; +} + +ConsoleInterface *ConsoleInterface::instance() +{ + return consoleinterface_instance; +} + +void ConsoleInterface::set_rcon(bool enable) +{ consoleinterface_rcon = enable; } -} // namespace sys +void ConsoleInterface::set_logsize(const size_t logsize) +{ + consoleinterface_logsize = logsize < 16 ? 16 : logsize; +} +void ConsoleInterface::event_text(const std::string & text) +{ + if (rcon()) { + consoleinterface_rconbuf.push_back(text); + } else { + while (consoleinterface_log.size() >= consoleinterface_logsize) { + consoleinterface_log.pop_front(); + } + + consoleinterface_log.push_back(std::string(text)); + print(text); + } +} + +void ConsoleInterface::print(const std::string & text) +{ + fallback_print(text); + std::cout << std::endl; +} + +} // namespace sys diff --git a/src/sys/consoleinterface.h b/src/sys/consoleinterface.h index 5411cb6..3a7d3ed 100644 --- a/src/sys/consoleinterface.h +++ b/src/sys/consoleinterface.h @@ -8,89 +8,141 @@ #define __INCLUDED_SYS_CONSOLEINTERFACE_H__ #include +#include +#include +#include #include #include #include "sys/sys.h" -/// global define to send a message to the system console -#define con_print sys::ConsoleInterface::instance()->messagestream() -/// global define to send a warning message to the system console -#define con_warn sys::ConsoleInterface::instance()->warningstream() -/// global define to send an error message to the system console -#define con_error sys::ConsoleInterface::instance()->errorstream() - -#ifdef HAVE_DEBUG_MESSAGES -/// global define to send a debug message to the system console -#define con_debug sys::ConsoleInterface::instance()->debugstream() -#else -#define con_debug if (0) *(std::ostream*)(0) -#endif namespace sys { -const size_t MAXCONLINES = 2048; +/// true if ANSI colors are enabled +bool ansi(); -/// interface for the client and server Console classes -class ConsoleInterface -{ -public: - /// default constructor - ConsoleInterface(); +/// enable or disable ANSI colors +void set_ansi(bool enable = true); - /// default destructor - virtual ~ConsoleInterface(); - - /// stream to send normal messages to - std::ostream & messagestream(); +/* -- ConsoleBuffer ------------------------------------------------ */ - /// stream to send warning messages to - std::ostream & warningstream(); +typedef std::char_traits Traits; - /// stream to send error messages to - std::ostream & errorstream(); +/// buffer back-end for console output +class ConsoleBuffer : public std::basic_streambuf +{ +public: + const std::string & str() const + { + return con_buffer; + } + +protected: + /// stream overflow + virtual int overflow(int c = Traits::eof()); + +private: + std::string con_buffer; +}; - /// stream to send debug messages to - std::ostream & debugstream(); - /// flush buffered messages - virtual void flush(); +/* -- ConsoleStream ------------------------------------------------ */ - /// resize the console (ncurses stub) - virtual void resize(); +/// provides global streams for console output +class ConsoleStream : public std::basic_ostream +{ +public: + ConsoleStream(); + ~ConsoleStream(); + + inline ConsoleBuffer & buf() + { + return con_buffer; + } + +private: + ConsoleBuffer con_buffer; +}; - /// return the console inputbuffer - inline std::stringstream & buffer() { return consoleinterface_buffer; } +/// global console output stream +extern ConsoleStream con_out; - inline bool rcon() { return consoleinterface_rcon; } - inline bool ansi() { return consoleinterface_ansi; } +/* -- Console ------------------------------------------------------ */ - /// enable or disable ANSI escape sequences - void set_ansi(bool enable = true); +/// interface for the client and server Console classes +class ConsoleInterface +{ +public: + /// default constructor + ConsoleInterface(); + + /// default destructor + virtual ~ConsoleInterface(); + + /// set maximal number of lines in the log + void set_logsize(const size_t logsize); + + /// return rcon state + inline bool rcon() + { + return consoleinterface_rcon; + } + /// enable or disable rcon void set_rcon(bool enable = true); - + + typedef std::deque Text; + + inline Text & rconbuf() + { + return consoleinterface_rconbuf; + } + + inline Text & log() + { + return consoleinterface_log; + } + /// a pointer to the current console instance static ConsoleInterface *instance(); - + + /// incoming text event handler + void event_text(const std::string & text); + + /// ncurses resize event + virtual void resize() + {}; + protected: - std::deque consoleinterface_text; - std::stringstream consoleinterface_buffer; + /// print one line of text + virtual void print(const std::string & text); - /// print a string to stdout with ansi color codes - void print_ansi(const char *line); - private: /// console singleton static ConsoleInterface *consoleinterface_instance; - bool consoleinterface_ansi; + bool consoleinterface_rcon; + Text consoleinterface_rconbuf; + + Text consoleinterface_log; + size_t consoleinterface_logsize; }; } // namespace sys +#define con_print sys::con_out << "^N" +#define con_warn sys::con_out << "^W" +#define con_error sys::con_out << "^R" +#ifdef HAVE_DEBUG_MESSAGES +#define con_debug sys::con_out << "^D" +#else +#define con_debug if (0) *(std::ostream*)(0) +#endif + + #endif // __INCLUDED_SYS_CONSOLEINTERFACE_H__ diff --git a/src/sys/sys.cc b/src/sys/sys.cc index db2be4d..59ed11d 100644 --- a/src/sys/sys.cc +++ b/src/sys/sys.cc @@ -29,18 +29,19 @@ #include "sys/sys.h" -namespace sys { +namespace sys +{ -bool isdirectory(std::string const &path) +bool isdirectory(const std::string &path) { #ifdef _WIN32 struct ::_stat path_stat; memset(&path_stat, 0, sizeof(struct ::_stat)); - + if (::_stat(path.c_str(), &path_stat) != 0) { return false; } - + if (path_stat.st_mode & _S_IFDIR) { return true; } @@ -48,11 +49,11 @@ bool isdirectory(std::string const &path) #else struct stat path_stat; memset(&path_stat, 0, sizeof(path_stat)); - + if (stat(path.c_str(), &path_stat) != 0) { return false; } - + if (path_stat.st_mode & S_IFDIR) { return true; } @@ -61,7 +62,7 @@ bool isdirectory(std::string const &path) #endif } -void mkdir(std::string const &path) +void mkdir(const std::string &path) { #ifdef _WIN32 std::string p(path); @@ -69,7 +70,7 @@ void mkdir(std::string const &path) if (p[i] == '/') p[i] = '\\'; if (p.size() && (p[p.size()-1] == '\\')) p.erase(p.size() -1, 1); - + if (_mkdir(p.c_str()) != 0) { con_warn << "Could not create directory '" << p << "'" << std::endl; } @@ -83,23 +84,23 @@ void signal(int signum, signalfunc handler) { #ifndef _WIN32 struct sigaction sa; - + sa.sa_sigaction = 0; memset(&sa.sa_mask, 0 ,sizeof(sigset_t)); sa.sa_flags = 0; sa.sa_handler = handler; - + ::sigaction(signum, &sa, 0); #endif } -unsigned long time() +unsigned long time() { #ifndef _WIN32 struct ::tm localtime; time_t epochtime = ::time(0); ::localtime_r(&epochtime, &localtime); - return ((unsigned long) (localtime.tm_sec + localtime.tm_min*60 + localtime.tm_hour*3600)); + return ((unsigned long)(localtime.tm_sec + localtime.tm_min*60 + localtime.tm_hour*3600)); #else return 0; #endif @@ -108,13 +109,14 @@ unsigned long time() void sleep(float seconds) { #ifndef _WIN32 - ::usleep((useconds_t) (seconds * 1000000.0f) ); + ::usleep((useconds_t)(seconds * 1000000.0f)); #else - Sleep((DWORD) (seconds*1000.0f)); + Sleep((DWORD)(seconds*1000.0f)); #endif } -void quit(int status) { +void quit(int status) +{ ::exit(status); } diff --git a/src/sys/sys.h b/src/sys/sys.h index 66040f0..81eba94 100644 --- a/src/sys/sys.h +++ b/src/sys/sys.h @@ -19,18 +19,18 @@ */ namespace sys { -typedef void (* signalfunc)(int signum); +typedef void(* signalfunc)(int signum); -/// check if a path exists and if it is a directory -bool isdirectory(std::string const &path); +/// returns true if a path exists and it is a directory +bool isdirectory(const std::string &path); /// create a directory -void mkdir(std::string const &path); +void mkdir(const std::string &path); /// intercept OS signals void signal(int signum, signalfunc handler); -/** +/** * @brief operation system exit() application * @param status return value */ diff --git a/src/ui/container.cc b/src/ui/container.cc index d544244..5a12e8e 100644 --- a/src/ui/container.cc +++ b/src/ui/container.cc @@ -30,12 +30,12 @@ Container::~Container() void Container::resize() { float w = container_childsize.width() * 1.5f; - float h = children().size() * container_childsize.height() + (children().size()+1) * container_margin; + float h = children().size() * (container_childsize.height() + margin()) + container_childsize.height(); set_size(w, h); const float x = container_childsize.width() * 0.25f; - float y = container_margin; + float y = container_childsize.height() * 0.5f; // reposition all children within the container for (Children::iterator it = children().begin(); it != children().end(); it++) { diff --git a/src/ui/input.cc b/src/ui/input.cc index 5e000d2..8113354 100644 --- a/src/ui/input.cc +++ b/src/ui/input.cc @@ -8,7 +8,6 @@ #include "ui/paint.h" #include "auxiliary/functions.h" #include "core/core.h" -#include "render/render.h" namespace ui { @@ -52,7 +51,7 @@ void Input::draw() draw_background(); draw_border(); - size_t text_width = (size_t) width() / font()->width(); + size_t text_width = (size_t) floorf(width() / font()->width()); math::Vector2f v(global_location()); paint::color(palette()->foreground()); @@ -74,7 +73,7 @@ void Input::draw() while (*c && draw_width > text_width - 2) { if (aux::is_color_code(c)) { c++; - render::Text::setcolor(*c); + paint::color_code(*c); } else { draw_width--; } @@ -89,7 +88,7 @@ void Input::draw() v.x += draw_width * font()->width(); if (input_pos < input_text.size()) { if (input_pos > 1 && aux::is_color_code(input_text.c_str() + input_pos -1)) { - render::Text::setcolor(input_text[input_pos]); + paint::color_code(input_text[input_pos]); } // limit to width std::string secondpart; @@ -119,6 +118,7 @@ bool Input::on_keypress(const int key, const unsigned int modifier) { switch (key) { case SDLK_TAB: + // FIXME should not be here core::CommandBuffer::complete(input_text, input_pos); return true; break; diff --git a/src/ui/paint.cc b/src/ui/paint.cc index 33ee54f..d50e3b5 100644 --- a/src/ui/paint.cc +++ b/src/ui/paint.cc @@ -27,9 +27,9 @@ void color(math::Color const & color) render::gl::color(color); } -void color_code(const char *c) +void color_code(const char c) { - render::Text::setcolor(*c); + render::Text::setcolor(c); } void border(math::Vector2f const &location, math::Vector2f const &size) diff --git a/src/ui/paint.h b/src/ui/paint.h index 367b001..c90f1b5 100644 --- a/src/ui/paint.h +++ b/src/ui/paint.h @@ -22,7 +22,7 @@ void color(float r=0.0f, float g=0.0f, float b=0.0f, float a=1.0f); void color(math::Color const & color); /// set paint color -void color_code(const char *c); +void color_code(const char c); /// draw a border void border(math::Vector2f const &location, math::Vector2f const &size); @@ -33,12 +33,12 @@ void rectangle(math::Vector2f const &location, math::Vector2f const &size); /// draw a rectangular bitmap void bitmap(math::Vector2f const &location, math::Vector2f const &size, std::string const &texture); -/// draw text +/// draw one line of text from a string void text(math::Vector2f const &location, math::Vector2f const &size, Font const *font, std::string const &text, unsigned int align = AlignCenter); - -/// draw textstream -void text(math::Vector2f const &location, Font const *font, std::stringstream & textstream); + +/// draw unaligned text from a stringstream +void text(math::Vector2f const &location, Font const *font, std::stringstream & textstream); } diff --git a/src/ui/ui.cc b/src/ui/ui.cc index 2cadd8b..baedd38 100644 --- a/src/ui/ui.cc +++ b/src/ui/ui.cc @@ -381,13 +381,12 @@ void UI::show_menu(const char *label) } else { menu->clear_previous(); } - ui_active_menu = menu; - ui_active_menu->event_resize(); - ui_active_menu->raise(); - ui_active_menu->show(); - ui_active_menu->set_focus(); ui_mouse_focus = this; ui_input_focus = this; + + ui_active_menu = menu; + ui_active_menu->event_resize(); + ui_active_menu->show(); } else { con_warn << "Unknown window '" << label << "'" << std::endl; } @@ -436,20 +435,22 @@ void UI::input_mouse(const float x, const float y) ui_mouse_focus = f; } -void UI::input_key(const bool pressed, const int key, const unsigned int modifier) +bool UI::input_key(const bool pressed, const int key, const unsigned int modifier) { + bool handled = false; if (key < 512) { // keyboard keys Widget *f = find_input_focus(); if (f) { - f->event_key(pressed, key, modifier); + handled = f->event_key(pressed, key, modifier); } ui_input_focus = f; } else { // mosue buttons if (ui_mouse_focus) - ui_mouse_focus->event_key(pressed, key, modifier); + handled = ui_mouse_focus->event_key(pressed, key, modifier); } + return handled; } /* -- event handlers ----------------------------------------------- */ @@ -459,12 +460,28 @@ void UI::input_key(const bool pressed, const int key, const unsigned int modifie */ bool UI::on_keypress(const int key, const unsigned int modifier) { - return true; + switch( key ) { + + case SDLK_ESCAPE: + if (active()) { + previous_menu(); + } else { + if (core::application()->connected()) { + show_menu("game"); + } + } + return true; + break; + default: + break; + } + + return false; } bool UI::on_keyrelease(const int key, const unsigned int modifier) { - return true; + return false; } } diff --git a/src/ui/ui.h b/src/ui/ui.h index 583f76c..8fa32c2 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -61,7 +61,7 @@ public: void input_mouse(const float x, const float y); /// receive global key input - void input_key(const bool pressed, const int key, const unsigned int modifier); + bool input_key(const bool pressed, const int key, const unsigned int modifier); /// run a user interface frame void frame(); diff --git a/src/ui/widget.cc b/src/ui/widget.cc index 1ecfcc8..24dfe5c 100644 --- a/src/ui/widget.cc +++ b/src/ui/widget.cc @@ -128,6 +128,20 @@ void Widget::show() void Widget::hide() { widget_visible = false; + if (parent() && focus()) { + Widget::Children::reverse_iterator it = parent()->children().rbegin(); + + while (it != parent()->children().rend()) { + Widget *w = (*it); + if (w != this && w->visible()) { + widget_focus = false; + w->widget_focus = true; + it = parent()->children().rend(); + } else { + it++; + } + } + } } diff --git a/src/ui/window.cc b/src/ui/window.cc index e79262f..3015a10 100644 --- a/src/ui/window.cc +++ b/src/ui/window.cc @@ -23,11 +23,16 @@ Window::~Window() { } -void Window::show() { +void Window::show() +{ resize(); Widget::show(); raise(); - set_focus(); + Widget *w = this; + while (w && w->visible()) { + w->set_focus(); + w = w->parent(); + } } void Window::set_previous(Window *previous) diff --git a/src/ui/window.h b/src/ui/window.h index 2c0e2a5..412d1f1 100644 --- a/src/ui/window.h +++ b/src/ui/window.h @@ -12,6 +12,7 @@ namespace ui { +/// a user interface window class Window : public Widget { @@ -27,7 +28,9 @@ public: /// clear the label of the previous window void clear_previous(); - /// showing a window sets focus + /// show the window + /**show() sets focus on the window and all of its parents + */ virtual void show(); inline const std::string &previous() const { -- cgit v1.2.3