summaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
authorTriBlade9 <triblade9@mail.com>2015-01-16 14:54:26 +0800
committerEkdohibs <nathanael.courant@laposte.net>2016-05-31 17:34:29 +0200
commit1d40385d4aacf0cbea4b19ff06940e8c9bebaf47 (patch)
tree39732d23598a1c14d514ff35d241f9499f0a3c13 /src/client
parent0e44af9f7056a78a8e561f708751acceacd149c1 (diff)
downloadminetest-1d40385d4aacf0cbea4b19ff06940e8c9bebaf47.tar.gz
minetest-1d40385d4aacf0cbea4b19ff06940e8c9bebaf47.tar.bz2
minetest-1d40385d4aacf0cbea4b19ff06940e8c9bebaf47.zip
Colored chat working as expected for both freetype and non-freetype builds. @nerzhul improvements * Add unit tests * Fix coding style * move guiChatConsole.hpp to client/
Diffstat (limited to 'src/client')
-rw-r--r--src/client/CMakeLists.txt1
-rw-r--r--src/client/guiChatConsole.cpp664
-rw-r--r--src/client/guiChatConsole.h138
3 files changed, 803 insertions, 0 deletions
diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt
index a1ec37fe3..bcf114760 100644
--- a/src/client/CMakeLists.txt
+++ b/src/client/CMakeLists.txt
@@ -1,5 +1,6 @@
set(client_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/clientlauncher.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/guiChatConsole.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile.cpp
PARENT_SCOPE
)
diff --git a/src/client/guiChatConsole.cpp b/src/client/guiChatConsole.cpp
new file mode 100644
index 000000000..d8837556a
--- /dev/null
+++ b/src/client/guiChatConsole.cpp
@@ -0,0 +1,664 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "guiChatConsole.h"
+#include "chat.h"
+#include "client.h"
+#include "debug.h"
+#include "gettime.h"
+#include "keycode.h"
+#include "settings.h"
+#include "porting.h"
+#include "client/tile.h"
+#include "fontengine.h"
+#include "log.h"
+#include "gettext.h"
+#include <string>
+
+#if USE_FREETYPE
+ #include "xCGUITTFont.h"
+#endif
+
+inline u32 clamp_u8(s32 value)
+{
+ return (u32) MYMIN(MYMAX(value, 0), 255);
+}
+
+
+GUIChatConsole::GUIChatConsole(
+ gui::IGUIEnvironment* env,
+ gui::IGUIElement* parent,
+ s32 id,
+ ChatBackend* backend,
+ Client* client,
+ IMenuManager* menumgr
+):
+ IGUIElement(gui::EGUIET_ELEMENT, env, parent, id,
+ core::rect<s32>(0,0,100,100)),
+ m_chat_backend(backend),
+ m_client(client),
+ m_menumgr(menumgr),
+ m_screensize(v2u32(0,0)),
+ m_animate_time_old(0),
+ m_open(false),
+ m_close_on_enter(false),
+ m_height(0),
+ m_desired_height(0),
+ m_desired_height_fraction(0.0),
+ m_height_speed(5.0),
+ m_open_inhibited(0),
+ m_cursor_blink(0.0),
+ m_cursor_blink_speed(0.0),
+ m_cursor_height(0.0),
+ m_background(NULL),
+ m_background_color(255, 0, 0, 0),
+ m_font(NULL),
+ m_fontsize(0, 0)
+{
+ m_animate_time_old = getTimeMs();
+
+ // load background settings
+ s32 console_alpha = g_settings->getS32("console_alpha");
+ m_background_color.setAlpha(clamp_u8(console_alpha));
+
+ // load the background texture depending on settings
+ ITextureSource *tsrc = client->getTextureSource();
+ if (tsrc->isKnownSourceImage("background_chat.jpg")) {
+ m_background = tsrc->getTexture("background_chat.jpg");
+ m_background_color.setRed(255);
+ m_background_color.setGreen(255);
+ m_background_color.setBlue(255);
+ } else {
+ v3f console_color = g_settings->getV3F("console_color");
+ m_background_color.setRed(clamp_u8(myround(console_color.X)));
+ m_background_color.setGreen(clamp_u8(myround(console_color.Y)));
+ m_background_color.setBlue(clamp_u8(myround(console_color.Z)));
+ }
+
+ m_font = g_fontengine->getFont(FONT_SIZE_UNSPECIFIED, FM_Mono);
+
+ if (m_font == NULL)
+ {
+ errorstream << "GUIChatConsole: Unable to load mono font ";
+ }
+ else
+ {
+ core::dimension2d<u32> dim = m_font->getDimension(L"M");
+ m_fontsize = v2u32(dim.Width, dim.Height);
+ m_font->grab();
+ }
+ m_fontsize.X = MYMAX(m_fontsize.X, 1);
+ m_fontsize.Y = MYMAX(m_fontsize.Y, 1);
+
+ // set default cursor options
+ setCursor(true, true, 2.0, 0.1);
+}
+
+GUIChatConsole::~GUIChatConsole()
+{
+ if (m_font)
+ m_font->drop();
+}
+
+void GUIChatConsole::openConsole(f32 height)
+{
+ m_open = true;
+ m_desired_height_fraction = height;
+ m_desired_height = height * m_screensize.Y;
+ reformatConsole();
+ m_animate_time_old = getTimeMs();
+ IGUIElement::setVisible(true);
+ Environment->setFocus(this);
+ m_menumgr->createdMenu(this);
+}
+
+bool GUIChatConsole::isOpen() const
+{
+ return m_open;
+}
+
+bool GUIChatConsole::isOpenInhibited() const
+{
+ return m_open_inhibited > 0;
+}
+
+void GUIChatConsole::closeConsole()
+{
+ m_open = false;
+ Environment->removeFocus(this);
+ m_menumgr->deletingMenu(this);
+}
+
+void GUIChatConsole::closeConsoleAtOnce()
+{
+ closeConsole();
+ m_height = 0;
+ recalculateConsolePosition();
+}
+
+f32 GUIChatConsole::getDesiredHeight() const
+{
+ return m_desired_height_fraction;
+}
+
+void GUIChatConsole::replaceAndAddToHistory(std::wstring line)
+{
+ ChatPrompt& prompt = m_chat_backend->getPrompt();
+ prompt.addToHistory(prompt.getLine());
+ prompt.replace(line);
+}
+
+
+void GUIChatConsole::setCursor(
+ bool visible, bool blinking, f32 blink_speed, f32 relative_height)
+{
+ if (visible)
+ {
+ if (blinking)
+ {
+ // leave m_cursor_blink unchanged
+ m_cursor_blink_speed = blink_speed;
+ }
+ else
+ {
+ m_cursor_blink = 0x8000; // on
+ m_cursor_blink_speed = 0.0;
+ }
+ }
+ else
+ {
+ m_cursor_blink = 0; // off
+ m_cursor_blink_speed = 0.0;
+ }
+ m_cursor_height = relative_height;
+}
+
+void GUIChatConsole::draw()
+{
+ if(!IsVisible)
+ return;
+
+ video::IVideoDriver* driver = Environment->getVideoDriver();
+
+ // Check screen size
+ v2u32 screensize = driver->getScreenSize();
+ if (screensize != m_screensize)
+ {
+ // screen size has changed
+ // scale current console height to new window size
+ if (m_screensize.Y != 0)
+ m_height = m_height * screensize.Y / m_screensize.Y;
+ m_desired_height = m_desired_height_fraction * m_screensize.Y;
+ m_screensize = screensize;
+ reformatConsole();
+ }
+
+ // Animation
+ u32 now = getTimeMs();
+ animate(now - m_animate_time_old);
+ m_animate_time_old = now;
+
+ // Draw console elements if visible
+ if (m_height > 0)
+ {
+ drawBackground();
+ drawText();
+ drawPrompt();
+ }
+
+ gui::IGUIElement::draw();
+}
+
+void GUIChatConsole::reformatConsole()
+{
+ s32 cols = m_screensize.X / m_fontsize.X - 2; // make room for a margin (looks better)
+ s32 rows = m_desired_height / m_fontsize.Y - 1; // make room for the input prompt
+ if (cols <= 0 || rows <= 0)
+ cols = rows = 0;
+ m_chat_backend->reformat(cols, rows);
+}
+
+void GUIChatConsole::recalculateConsolePosition()
+{
+ core::rect<s32> rect(0, 0, m_screensize.X, m_height);
+ DesiredRect = rect;
+ recalculateAbsolutePosition(false);
+}
+
+void GUIChatConsole::animate(u32 msec)
+{
+ // animate the console height
+ s32 goal = m_open ? m_desired_height : 0;
+
+ // Set invisible if close animation finished (reset by openConsole)
+ // This function (animate()) is never called once its visibility becomes false so do not
+ // actually set visible to false before the inhibited period is over
+ if (!m_open && m_height == 0 && m_open_inhibited == 0)
+ IGUIElement::setVisible(false);
+
+ if (m_height != goal)
+ {
+ s32 max_change = msec * m_screensize.Y * (m_height_speed / 1000.0);
+ if (max_change == 0)
+ max_change = 1;
+
+ if (m_height < goal)
+ {
+ // increase height
+ if (m_height + max_change < goal)
+ m_height += max_change;
+ else
+ m_height = goal;
+ }
+ else
+ {
+ // decrease height
+ if (m_height > goal + max_change)
+ m_height -= max_change;
+ else
+ m_height = goal;
+ }
+
+ recalculateConsolePosition();
+ }
+
+ // blink the cursor
+ if (m_cursor_blink_speed != 0.0)
+ {
+ u32 blink_increase = 0x10000 * msec * (m_cursor_blink_speed / 1000.0);
+ if (blink_increase == 0)
+ blink_increase = 1;
+ m_cursor_blink = ((m_cursor_blink + blink_increase) & 0xffff);
+ }
+
+ // decrease open inhibit counter
+ if (m_open_inhibited > msec)
+ m_open_inhibited -= msec;
+ else
+ m_open_inhibited = 0;
+}
+
+void GUIChatConsole::drawBackground()
+{
+ video::IVideoDriver* driver = Environment->getVideoDriver();
+ if (m_background != NULL)
+ {
+ core::rect<s32> sourcerect(0, -m_height, m_screensize.X, 0);
+ driver->draw2DImage(
+ m_background,
+ v2s32(0, 0),
+ sourcerect,
+ &AbsoluteClippingRect,
+ m_background_color,
+ false);
+ }
+ else
+ {
+ driver->draw2DRectangle(
+ m_background_color,
+ core::rect<s32>(0, 0, m_screensize.X, m_height),
+ &AbsoluteClippingRect);
+ }
+}
+
+void GUIChatConsole::drawText()
+{
+ if (m_font == NULL)
+ return;
+
+ ChatBuffer& buf = m_chat_backend->getConsoleBuffer();
+ for (u32 row = 0; row < buf.getRows(); ++row)
+ {
+ const ChatFormattedLine& line = buf.getFormattedLine(row);
+ if (line.fragments.empty())
+ continue;
+
+ s32 line_height = m_fontsize.Y;
+ s32 y = row * line_height + m_height - m_desired_height;
+ if (y + line_height < 0)
+ continue;
+
+ for (u32 i = 0; i < line.fragments.size(); ++i)
+ {
+ const ChatFormattedFragment& fragment = line.fragments[i];
+ s32 x = (fragment.column + 1) * m_fontsize.X;
+ core::rect<s32> destrect(
+ x, y, x + m_fontsize.X * fragment.text.size(), y + m_fontsize.Y);
+
+
+ #if USE_FREETYPE
+ // Draw colored text if FreeType is enabled
+ irr::gui::CGUITTFont *tmp = static_cast<irr::gui::CGUITTFont*>(m_font);
+ tmp->draw(
+ fragment.text.c_str(),
+ destrect,
+ fragment.text.getColors(),
+ false,
+ false,
+ &AbsoluteClippingRect);
+ #else
+ // Otherwise use standard text
+ m_font->draw(
+ fragment.text.c_str(),
+ destrect,
+ video::SColor(255, 255, 255, 255),
+ false,
+ false,
+ &AbsoluteClippingRect);
+ #endif
+ }
+ }
+}
+
+void GUIChatConsole::drawPrompt()
+{
+ if (m_font == NULL)
+ return;
+
+ u32 row = m_chat_backend->getConsoleBuffer().getRows();
+ s32 line_height = m_fontsize.Y;
+ s32 y = row * line_height + m_height - m_desired_height;
+
+ ChatPrompt& prompt = m_chat_backend->getPrompt();
+ std::wstring prompt_text = prompt.getVisiblePortion();
+
+ // FIXME Draw string at once, not character by character
+ // That will only work with the cursor once we have a monospace font
+ for (u32 i = 0; i < prompt_text.size(); ++i)
+ {
+ wchar_t ws[2] = {prompt_text[i], 0};
+ s32 x = (1 + i) * m_fontsize.X;
+ core::rect<s32> destrect(
+ x, y, x + m_fontsize.X, y + m_fontsize.Y);
+ m_font->draw(
+ ws,
+ destrect,
+ video::SColor(255, 255, 255, 255),
+ false,
+ false,
+ &AbsoluteClippingRect);
+ }
+
+ // Draw the cursor during on periods
+ if ((m_cursor_blink & 0x8000) != 0)
+ {
+ s32 cursor_pos = prompt.getVisibleCursorPosition();
+ if (cursor_pos >= 0)
+ {
+ s32 cursor_len = prompt.getCursorLength();
+ video::IVideoDriver* driver = Environment->getVideoDriver();
+ s32 x = (1 + cursor_pos) * m_fontsize.X;
+ core::rect<s32> destrect(
+ x,
+ y + m_fontsize.Y * (1.0 - m_cursor_height),
+ x + m_fontsize.X * MYMAX(cursor_len, 1),
+ y + m_fontsize.Y * (cursor_len ? m_cursor_height+1 : 1)
+ );
+ video::SColor cursor_color(255,255,255,255);
+ driver->draw2DRectangle(
+ cursor_color,
+ destrect,
+ &AbsoluteClippingRect);
+ }
+ }
+
+}
+
+bool GUIChatConsole::OnEvent(const SEvent& event)
+{
+
+ ChatPrompt &prompt = m_chat_backend->getPrompt();
+
+ if(event.EventType == EET_KEY_INPUT_EVENT && event.KeyInput.PressedDown)
+ {
+ // Key input
+ if(KeyPress(event.KeyInput) == getKeySetting("keymap_console"))
+ {
+ closeConsole();
+
+ // inhibit open so the_game doesn't reopen immediately
+ m_open_inhibited = 50;
+ m_close_on_enter = false;
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_ESCAPE)
+ {
+ closeConsoleAtOnce();
+ m_close_on_enter = false;
+ // inhibit open so the_game doesn't reopen immediately
+ m_open_inhibited = 1; // so the ESCAPE button doesn't open the "pause menu"
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_PRIOR)
+ {
+ m_chat_backend->scrollPageUp();
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_NEXT)
+ {
+ m_chat_backend->scrollPageDown();
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_RETURN)
+ {
+ prompt.addToHistory(prompt.getLine());
+ std::wstring text = prompt.replace(L"");
+ m_client->typeChatMessage(text);
+ if (m_close_on_enter) {
+ closeConsoleAtOnce();
+ m_close_on_enter = false;
+ }
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_UP)
+ {
+ // Up pressed
+ // Move back in history
+ prompt.historyPrev();
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_DOWN)
+ {
+ // Down pressed
+ // Move forward in history
+ prompt.historyNext();
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_LEFT || event.KeyInput.Key == KEY_RIGHT)
+ {
+ // Left/right pressed
+ // Move/select character/word to the left depending on control and shift keys
+ ChatPrompt::CursorOp op = event.KeyInput.Shift ?
+ ChatPrompt::CURSOROP_SELECT :
+ ChatPrompt::CURSOROP_MOVE;
+ ChatPrompt::CursorOpDir dir = event.KeyInput.Key == KEY_LEFT ?
+ ChatPrompt::CURSOROP_DIR_LEFT :
+ ChatPrompt::CURSOROP_DIR_RIGHT;
+ ChatPrompt::CursorOpScope scope = event.KeyInput.Control ?
+ ChatPrompt::CURSOROP_SCOPE_WORD :
+ ChatPrompt::CURSOROP_SCOPE_CHARACTER;
+ prompt.cursorOperation(op, dir, scope);
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_HOME)
+ {
+ // Home pressed
+ // move to beginning of line
+ prompt.cursorOperation(
+ ChatPrompt::CURSOROP_MOVE,
+ ChatPrompt::CURSOROP_DIR_LEFT,
+ ChatPrompt::CURSOROP_SCOPE_LINE);
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_END)
+ {
+ // End pressed
+ // move to end of line
+ prompt.cursorOperation(
+ ChatPrompt::CURSOROP_MOVE,
+ ChatPrompt::CURSOROP_DIR_RIGHT,
+ ChatPrompt::CURSOROP_SCOPE_LINE);
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_BACK)
+ {
+ // Backspace or Ctrl-Backspace pressed
+ // delete character / word to the left
+ ChatPrompt::CursorOpScope scope =
+ event.KeyInput.Control ?
+ ChatPrompt::CURSOROP_SCOPE_WORD :
+ ChatPrompt::CURSOROP_SCOPE_CHARACTER;
+ prompt.cursorOperation(
+ ChatPrompt::CURSOROP_DELETE,
+ ChatPrompt::CURSOROP_DIR_LEFT,
+ scope);
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_DELETE)
+ {
+ // Delete or Ctrl-Delete pressed
+ // delete character / word to the right
+ ChatPrompt::CursorOpScope scope =
+ event.KeyInput.Control ?
+ ChatPrompt::CURSOROP_SCOPE_WORD :
+ ChatPrompt::CURSOROP_SCOPE_CHARACTER;
+ prompt.cursorOperation(
+ ChatPrompt::CURSOROP_DELETE,
+ ChatPrompt::CURSOROP_DIR_RIGHT,
+ scope);
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_KEY_A && event.KeyInput.Control)
+ {
+ // Ctrl-A pressed
+ // Select all text
+ prompt.cursorOperation(
+ ChatPrompt::CURSOROP_SELECT,
+ ChatPrompt::CURSOROP_DIR_LEFT, // Ignored
+ ChatPrompt::CURSOROP_SCOPE_LINE);
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_KEY_C && event.KeyInput.Control)
+ {
+ // Ctrl-C pressed
+ // Copy text to clipboard
+ if (prompt.getCursorLength() <= 0)
+ return true;
+ std::wstring wselected = prompt.getSelection();
+ std::string selected(wselected.begin(), wselected.end());
+ Environment->getOSOperator()->copyToClipboard(selected.c_str());
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_KEY_V && event.KeyInput.Control)
+ {
+ // Ctrl-V pressed
+ // paste text from clipboard
+ if (prompt.getCursorLength() > 0) {
+ // Delete selected section of text
+ prompt.cursorOperation(
+ ChatPrompt::CURSOROP_DELETE,
+ ChatPrompt::CURSOROP_DIR_LEFT, // Ignored
+ ChatPrompt::CURSOROP_SCOPE_SELECTION);
+ }
+ IOSOperator *os_operator = Environment->getOSOperator();
+ const c8 *text = os_operator->getTextFromClipboard();
+ if (!text)
+ return true;
+ std::basic_string<unsigned char> str((const unsigned char*)text);
+ prompt.input(std::wstring(str.begin(), str.end()));
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_KEY_X && event.KeyInput.Control)
+ {
+ // Ctrl-X pressed
+ // Cut text to clipboard
+ if (prompt.getCursorLength() <= 0)
+ return true;
+ std::wstring wselected = prompt.getSelection();
+ std::string selected(wselected.begin(), wselected.end());
+ Environment->getOSOperator()->copyToClipboard(selected.c_str());
+ prompt.cursorOperation(
+ ChatPrompt::CURSOROP_DELETE,
+ ChatPrompt::CURSOROP_DIR_LEFT, // Ignored
+ ChatPrompt::CURSOROP_SCOPE_SELECTION);
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_KEY_U && event.KeyInput.Control)
+ {
+ // Ctrl-U pressed
+ // kill line to left end
+ prompt.cursorOperation(
+ ChatPrompt::CURSOROP_DELETE,
+ ChatPrompt::CURSOROP_DIR_LEFT,
+ ChatPrompt::CURSOROP_SCOPE_LINE);
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_KEY_K && event.KeyInput.Control)
+ {
+ // Ctrl-K pressed
+ // kill line to right end
+ prompt.cursorOperation(
+ ChatPrompt::CURSOROP_DELETE,
+ ChatPrompt::CURSOROP_DIR_RIGHT,
+ ChatPrompt::CURSOROP_SCOPE_LINE);
+ return true;
+ }
+ else if(event.KeyInput.Key == KEY_TAB)
+ {
+ // Tab or Shift-Tab pressed
+ // Nick completion
+ std::list<std::string> names = m_client->getConnectedPlayerNames();
+ bool backwards = event.KeyInput.Shift;
+ prompt.nickCompletion(names, backwards);
+ return true;
+ }
+ else if(event.KeyInput.Char != 0 && !event.KeyInput.Control)
+ {
+ #if (defined(linux) || defined(__linux))
+ wchar_t wc = L'_';
+ mbtowc( &wc, (char *) &event.KeyInput.Char, sizeof(event.KeyInput.Char) );
+ prompt.input(wc);
+ #else
+ prompt.input(event.KeyInput.Char);
+ #endif
+ return true;
+ }
+ }
+ else if(event.EventType == EET_MOUSE_INPUT_EVENT)
+ {
+ if(event.MouseInput.Event == EMIE_MOUSE_WHEEL)
+ {
+ s32 rows = myround(-3.0 * event.MouseInput.Wheel);
+ m_chat_backend->scroll(rows);
+ }
+ }
+
+ return Parent ? Parent->OnEvent(event) : false;
+}
+
+void GUIChatConsole::setVisible(bool visible)
+{
+ m_open = visible;
+ IGUIElement::setVisible(visible);
+ if (!visible) {
+ m_height = 0;
+ recalculateConsolePosition();
+ }
+}
+
diff --git a/src/client/guiChatConsole.h b/src/client/guiChatConsole.h
new file mode 100644
index 000000000..3013a1d31
--- /dev/null
+++ b/src/client/guiChatConsole.h
@@ -0,0 +1,138 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef GUICHATCONSOLE_HEADER
+#define GUICHATCONSOLE_HEADER
+
+#include "irrlichttypes_extrabloated.h"
+#include "modalMenu.h"
+#include "chat.h"
+#include "config.h"
+
+class Client;
+
+class GUIChatConsole : public gui::IGUIElement
+{
+public:
+ GUIChatConsole(gui::IGUIEnvironment* env,
+ gui::IGUIElement* parent,
+ s32 id,
+ ChatBackend* backend,
+ Client* client,
+ IMenuManager* menumgr);
+ virtual ~GUIChatConsole();
+
+ // Open the console (height = desired fraction of screen size)
+ // This doesn't open immediately but initiates an animation.
+ // You should call isOpenInhibited() before this.
+ void openConsole(f32 height);
+
+ bool isOpen() const;
+
+ // Check if the console should not be opened at the moment
+ // This is to avoid reopening the console immediately after closing
+ bool isOpenInhibited() const;
+ // Close the console, equivalent to openConsole(0).
+ // This doesn't close immediately but initiates an animation.
+ void closeConsole();
+ // Close the console immediately, without animation.
+ void closeConsoleAtOnce();
+ // Set whether to close the console after the user presses enter.
+ void setCloseOnEnter(bool close) { m_close_on_enter = close; }
+
+ // Return the desired height (fraction of screen size)
+ // Zero if the console is closed or getting closed
+ f32 getDesiredHeight() const;
+
+ // Replace actual line when adding the actual to the history (if there is any)
+ void replaceAndAddToHistory(std::wstring line);
+
+ // Change how the cursor looks
+ void setCursor(
+ bool visible,
+ bool blinking = false,
+ f32 blink_speed = 1.0,
+ f32 relative_height = 1.0);
+
+ // Irrlicht draw method
+ virtual void draw();
+
+ bool canTakeFocus(gui::IGUIElement* element) { return false; }
+
+ virtual bool OnEvent(const SEvent& event);
+
+ virtual void setVisible(bool visible);
+
+private:
+ void reformatConsole();
+ void recalculateConsolePosition();
+
+ // These methods are called by draw
+ void animate(u32 msec);
+ void drawBackground();
+ void drawText();
+ void drawPrompt();
+
+private:
+ ChatBackend* m_chat_backend;
+ Client* m_client;
+ IMenuManager* m_menumgr;
+
+ // current screen size
+ v2u32 m_screensize;
+
+ // used to compute how much time passed since last animate()
+ u32 m_animate_time_old;
+
+ // should the console be opened or closed?
+ bool m_open;
+ // should it close after you press enter?
+ bool m_close_on_enter;
+ // current console height [pixels]
+ s32 m_height;
+ // desired height [pixels]
+ f32 m_desired_height;
+ // desired height [screen height fraction]
+ f32 m_desired_height_fraction;
+ // console open/close animation speed [screen height fraction / second]
+ f32 m_height_speed;
+ // if nonzero, opening the console is inhibited [milliseconds]
+ u32 m_open_inhibited;
+
+ // cursor blink frame (16-bit value)
+ // cursor is off during [0,32767] and on during [32768,65535]
+ u32 m_cursor_blink;
+ // cursor blink speed [on/off toggles / second]
+ f32 m_cursor_blink_speed;
+ // cursor height [line height]
+ f32 m_cursor_height;
+
+ // background texture
+ video::ITexture* m_background;
+ // background color (including alpha)
+ video::SColor m_background_color;
+
+ // font
+ gui::IGUIFont* m_font;
+ v2u32 m_fontsize;
+};
+
+
+#endif
+