Chat console improvements (#124)
This commit is contained in:
parent
0019930f27
commit
a3f08fe31f
@ -35,6 +35,7 @@ ChatBuffer::ChatBuffer(u32 scrollback):
|
|||||||
if (m_scrollback == 0)
|
if (m_scrollback == 0)
|
||||||
m_scrollback = 1;
|
m_scrollback = 1;
|
||||||
m_empty_formatted_line.first = true;
|
m_empty_formatted_line.first = true;
|
||||||
|
m_empty_formatted_line.line_index = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatBuffer::addLine(const std::wstring &name, const std::wstring &text)
|
void ChatBuffer::addLine(const std::wstring &name, const std::wstring &text)
|
||||||
@ -47,7 +48,7 @@ void ChatBuffer::addLine(const std::wstring &name, const std::wstring &text)
|
|||||||
if (m_rows > 0) {
|
if (m_rows > 0) {
|
||||||
// m_formatted is valid and must be kept valid
|
// m_formatted is valid and must be kept valid
|
||||||
bool scrolled_at_bottom = (m_scroll == getBottomScrollPos());
|
bool scrolled_at_bottom = (m_scroll == getBottomScrollPos());
|
||||||
u32 num_added = formatChatLine(line, m_cols, m_formatted);
|
u32 num_added = formatChatLine(line, m_unformatted.size() - 1, m_cols, m_formatted);
|
||||||
if (scrolled_at_bottom)
|
if (scrolled_at_bottom)
|
||||||
m_scroll += num_added;
|
m_scroll += num_added;
|
||||||
}
|
}
|
||||||
@ -172,7 +173,7 @@ void ChatBuffer::reformat(u32 cols, u32 rows)
|
|||||||
{
|
{
|
||||||
if (i == restore_scroll_unformatted)
|
if (i == restore_scroll_unformatted)
|
||||||
restore_scroll_formatted = m_formatted.size();
|
restore_scroll_formatted = m_formatted.size();
|
||||||
formatChatLine(m_unformatted[i], cols, m_formatted);
|
formatChatLine(m_unformatted[i], i, cols, m_formatted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,7 +224,7 @@ void ChatBuffer::scrollBottom()
|
|||||||
m_scroll = getBottomScrollPos();
|
m_scroll = getBottomScrollPos();
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols,
|
u32 ChatBuffer::formatChatLine(const ChatLine& line, int line_index, u32 cols,
|
||||||
std::vector<ChatFormattedLine>& destination) const
|
std::vector<ChatFormattedLine>& destination) const
|
||||||
{
|
{
|
||||||
u32 num_added = 0;
|
u32 num_added = 0;
|
||||||
@ -266,6 +267,7 @@ u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols,
|
|||||||
//EnrichedString line_text(line.text);
|
//EnrichedString line_text(line.text);
|
||||||
|
|
||||||
next_line.first = true;
|
next_line.first = true;
|
||||||
|
next_line.line_index = line_index;
|
||||||
bool text_processing = false;
|
bool text_processing = false;
|
||||||
|
|
||||||
// Produce fragments and layout them into lines
|
// Produce fragments and layout them into lines
|
||||||
|
@ -67,6 +67,8 @@ struct ChatFormattedLine
|
|||||||
std::vector<ChatFormattedFragment> fragments;
|
std::vector<ChatFormattedFragment> fragments;
|
||||||
// true if first line of one formatted ChatLine
|
// true if first line of one formatted ChatLine
|
||||||
bool first;
|
bool first;
|
||||||
|
// Line index in ChatLine buffer
|
||||||
|
int line_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ChatBuffer
|
class ChatBuffer
|
||||||
@ -111,6 +113,9 @@ public:
|
|||||||
// Scroll to top of buffer (oldest)
|
// Scroll to top of buffer (oldest)
|
||||||
void scrollTop();
|
void scrollTop();
|
||||||
|
|
||||||
|
s32 getScrollPos() { return m_scroll; }
|
||||||
|
u32 getColsCount() { return m_cols; }
|
||||||
|
|
||||||
// Functions for keeping track of whether the lines were modified by any
|
// Functions for keeping track of whether the lines were modified by any
|
||||||
// preceding operations
|
// preceding operations
|
||||||
// If they were not changed, getLineCount() and getLine() output the same as
|
// If they were not changed, getLineCount() and getLine() output the same as
|
||||||
@ -121,11 +126,11 @@ public:
|
|||||||
// Format a chat line for the given number of columns.
|
// Format a chat line for the given number of columns.
|
||||||
// Appends the formatted lines to the destination array and
|
// Appends the formatted lines to the destination array and
|
||||||
// returns the number of formatted lines.
|
// returns the number of formatted lines.
|
||||||
u32 formatChatLine(const ChatLine& line, u32 cols,
|
u32 formatChatLine(const ChatLine& line, int line_index, u32 cols,
|
||||||
std::vector<ChatFormattedLine>& destination) const;
|
std::vector<ChatFormattedLine>& destination) const;
|
||||||
|
|
||||||
void resize(u32 scrollback);
|
void resize(u32 scrollback);
|
||||||
protected:
|
|
||||||
s32 getTopScrollPos() const;
|
s32 getTopScrollPos() const;
|
||||||
s32 getBottomScrollPos() const;
|
s32 getBottomScrollPos() const;
|
||||||
|
|
||||||
|
@ -954,10 +954,6 @@ private:
|
|||||||
#ifdef HAVE_TOUCHSCREENGUI
|
#ifdef HAVE_TOUCHSCREENGUI
|
||||||
bool m_cache_touchtarget;
|
bool m_cache_touchtarget;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__ANDROID__) || defined(__IOS__)
|
|
||||||
bool m_android_chat_open = false;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Game::Game() :
|
Game::Game() :
|
||||||
@ -1885,8 +1881,8 @@ void Game::processUserInput(f32 dtime)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!guienv->hasFocus(gui_chat_console) && gui_chat_console->isOpen()) {
|
if (!gui_chat_console->hasFocus() && gui_chat_console->isOpen()) {
|
||||||
gui_chat_console->closeConsoleAtOnce();
|
gui_chat_console->closeConsole();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Input handler step() (used by the random input generator)
|
// Input handler step() (used by the random input generator)
|
||||||
@ -1924,7 +1920,7 @@ void Game::processKeyInput()
|
|||||||
openInventory();
|
openInventory();
|
||||||
} else if (input->cancelPressed()) {
|
} else if (input->cancelPressed()) {
|
||||||
#if defined(__ANDROID__) || defined(__IOS__)
|
#if defined(__ANDROID__) || defined(__IOS__)
|
||||||
m_android_chat_open = false;
|
gui_chat_console->setAndroidChatOpen(false);
|
||||||
#endif
|
#endif
|
||||||
if (!gui_chat_console->isOpenInhibited()) {
|
if (!gui_chat_console->isOpenInhibited()) {
|
||||||
showPauseMenu();
|
showPauseMenu();
|
||||||
@ -2137,11 +2133,20 @@ void Game::openConsole(float scale, const wchar_t *line)
|
|||||||
{
|
{
|
||||||
assert(scale > 0.0f && scale <= 1.0f);
|
assert(scale > 0.0f && scale <= 1.0f);
|
||||||
|
|
||||||
|
if (gui_chat_console->getAndroidChatOpen())
|
||||||
|
return;
|
||||||
|
|
||||||
#if defined(__ANDROID__) || defined(__IOS__)
|
#if defined(__ANDROID__) || defined(__IOS__)
|
||||||
if (!porting::hasRealKeyboard()) {
|
if (!porting::hasRealKeyboard()) {
|
||||||
porting::showInputDialog("", "", 2);
|
porting::showInputDialog("", "", 2);
|
||||||
m_android_chat_open = true;
|
gui_chat_console->setAndroidChatOpen(true);
|
||||||
} else {
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
return;
|
||||||
|
#elif defined(__IOS__)
|
||||||
|
if (!g_settings->getBool("device_is_tablet"))
|
||||||
|
return;
|
||||||
#endif
|
#endif
|
||||||
if (gui_chat_console->isOpenInhibited())
|
if (gui_chat_console->isOpenInhibited())
|
||||||
return;
|
return;
|
||||||
@ -2150,18 +2155,19 @@ void Game::openConsole(float scale, const wchar_t *line)
|
|||||||
gui_chat_console->setCloseOnEnter(true);
|
gui_chat_console->setCloseOnEnter(true);
|
||||||
gui_chat_console->replaceAndAddToHistory(line);
|
gui_chat_console->replaceAndAddToHistory(line);
|
||||||
}
|
}
|
||||||
#if defined(__ANDROID__) || defined(__IOS__)
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__ANDROID__) || defined(__IOS__)
|
#if defined(__ANDROID__) || defined(__IOS__)
|
||||||
void Game::handleAndroidChatInput()
|
void Game::handleAndroidChatInput()
|
||||||
{
|
{
|
||||||
if (m_android_chat_open && porting::getInputDialogState() == 0) {
|
if (gui_chat_console->getAndroidChatOpen() &&
|
||||||
|
porting::getInputDialogState() == 0) {
|
||||||
std::string text = porting::getInputDialogValue();
|
std::string text = porting::getInputDialogValue();
|
||||||
client->typeChatMessage(utf8_to_wide(text));
|
client->typeChatMessage(utf8_to_wide(text));
|
||||||
m_android_chat_open = false;
|
gui_chat_console->setAndroidChatOpen(false);
|
||||||
|
if (!text.empty() && gui_chat_console->isOpen()) {
|
||||||
|
gui_chat_console->closeConsole();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
#include "util/numeric.h"
|
#include "util/numeric.h"
|
||||||
#include "inputhandler.h"
|
#include "inputhandler.h"
|
||||||
|
#include "gui/guiChatConsole.h"
|
||||||
#include "gui/mainmenumanager.h"
|
#include "gui/mainmenumanager.h"
|
||||||
#include "hud.h"
|
#include "hud.h"
|
||||||
|
|
||||||
@ -115,6 +116,13 @@ bool MyEventReceiver::OnEvent(const SEvent &event)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
GUIChatConsole* chat_console = GUIChatConsole::getChatConsole();
|
||||||
|
if (chat_console && chat_console->isOpen()) {
|
||||||
|
bool result = chat_console->preprocessEvent(event);
|
||||||
|
if (result)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
React to nothing here if a menu is active
|
React to nothing here if a menu is active
|
||||||
*/
|
*/
|
||||||
|
@ -45,6 +45,7 @@ inline u32 clamp_u8(s32 value)
|
|||||||
return (u32) MYMIN(MYMAX(value, 0), 255);
|
return (u32) MYMIN(MYMAX(value, 0), 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GUIChatConsole* GUIChatConsole::m_chat_console = nullptr;
|
||||||
|
|
||||||
GUIChatConsole::GUIChatConsole(
|
GUIChatConsole::GUIChatConsole(
|
||||||
gui::IGUIEnvironment* env,
|
gui::IGUIEnvironment* env,
|
||||||
@ -61,6 +62,8 @@ GUIChatConsole::GUIChatConsole(
|
|||||||
m_menumgr(menumgr),
|
m_menumgr(menumgr),
|
||||||
m_animate_time_old(porting::getTimeMs())
|
m_animate_time_old(porting::getTimeMs())
|
||||||
{
|
{
|
||||||
|
m_chat_console = this;
|
||||||
|
|
||||||
// load background settings
|
// load background settings
|
||||||
s32 console_alpha = g_settings->getS32("console_alpha");
|
s32 console_alpha = g_settings->getS32("console_alpha");
|
||||||
m_background_color.setAlpha(clamp_u8(console_alpha));
|
m_background_color.setAlpha(clamp_u8(console_alpha));
|
||||||
@ -93,12 +96,19 @@ GUIChatConsole::GUIChatConsole(
|
|||||||
m_fontsize.X = MYMAX(m_fontsize.X, 1);
|
m_fontsize.X = MYMAX(m_fontsize.X, 1);
|
||||||
m_fontsize.Y = MYMAX(m_fontsize.Y, 1);
|
m_fontsize.Y = MYMAX(m_fontsize.Y, 1);
|
||||||
|
|
||||||
|
createVScrollBar();
|
||||||
|
|
||||||
// set default cursor options
|
// set default cursor options
|
||||||
setCursor(true, true, 2.0, 0.1);
|
setCursor(true, true, 2.0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
GUIChatConsole::~GUIChatConsole()
|
GUIChatConsole::~GUIChatConsole()
|
||||||
{
|
{
|
||||||
|
m_chat_console = nullptr;
|
||||||
|
|
||||||
|
removeChild(m_vscrollbar);
|
||||||
|
delete m_vscrollbar;
|
||||||
|
|
||||||
#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
|
#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
|
||||||
if (porting::hasRealKeyboard() && SDL_IsTextInputActive())
|
if (porting::hasRealKeyboard() && SDL_IsTextInputActive())
|
||||||
SDL_StopTextInput();
|
SDL_StopTextInput();
|
||||||
@ -114,10 +124,17 @@ void GUIChatConsole::openConsole(f32 scale)
|
|||||||
|
|
||||||
m_open = true;
|
m_open = true;
|
||||||
m_desired_height_fraction = scale;
|
m_desired_height_fraction = scale;
|
||||||
|
|
||||||
|
if (g_settings->getU32("fps_max") < 60) {
|
||||||
|
m_desired_height_fraction *= m_screensize.Y;
|
||||||
|
m_height = m_desired_height_fraction;
|
||||||
|
}
|
||||||
|
|
||||||
m_desired_height = scale * m_screensize.Y;
|
m_desired_height = scale * m_screensize.Y;
|
||||||
reformatConsole();
|
reformatConsole();
|
||||||
m_animate_time_old = porting::getTimeMs();
|
m_animate_time_old = porting::getTimeMs();
|
||||||
IGUIElement::setVisible(true);
|
IGUIElement::setVisible(true);
|
||||||
|
m_vscrollbar->setVisible(true);
|
||||||
Environment->setFocus(this);
|
Environment->setFocus(this);
|
||||||
m_menumgr->createdMenu(this);
|
m_menumgr->createdMenu(this);
|
||||||
|
|
||||||
@ -143,17 +160,16 @@ void GUIChatConsole::closeConsole()
|
|||||||
Environment->removeFocus(this);
|
Environment->removeFocus(this);
|
||||||
m_menumgr->deletingMenu(this);
|
m_menumgr->deletingMenu(this);
|
||||||
|
|
||||||
|
if (g_settings->getU32("fps_max") < 60) {
|
||||||
|
m_height = 0;
|
||||||
|
recalculateConsolePosition();
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
|
#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
|
||||||
if (porting::hasRealKeyboard() && SDL_IsTextInputActive())
|
if (porting::hasRealKeyboard() && SDL_IsTextInputActive())
|
||||||
SDL_StopTextInput();
|
SDL_StopTextInput();
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
void GUIChatConsole::closeConsoleAtOnce()
|
|
||||||
{
|
|
||||||
closeConsole();
|
|
||||||
m_height = 0;
|
|
||||||
recalculateConsolePosition();
|
|
||||||
#ifdef HAVE_TOUCHSCREENGUI
|
#ifdef HAVE_TOUCHSCREENGUI
|
||||||
if (g_touchscreengui && g_touchscreengui->isActive())
|
if (g_touchscreengui && g_touchscreengui->isActive())
|
||||||
g_touchscreengui->show();
|
g_touchscreengui->show();
|
||||||
@ -197,6 +213,8 @@ void GUIChatConsole::draw()
|
|||||||
if(!IsVisible)
|
if(!IsVisible)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
updateVScrollBar();
|
||||||
|
|
||||||
video::IVideoDriver* driver = Environment->getVideoDriver();
|
video::IVideoDriver* driver = Environment->getVideoDriver();
|
||||||
|
|
||||||
// Check screen size
|
// Check screen size
|
||||||
@ -230,19 +248,24 @@ void GUIChatConsole::draw()
|
|||||||
|
|
||||||
void GUIChatConsole::reformatConsole()
|
void GUIChatConsole::reformatConsole()
|
||||||
{
|
{
|
||||||
s32 cols = m_screensize.X / m_fontsize.X - 2; // make room for a margin (looks better)
|
s32 cols = (m_screensize.X - m_scrollbar_width) / 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
|
s32 rows = m_desired_height / m_fontsize.Y - 1; // make room for the input prompt
|
||||||
if (cols <= 0 || rows <= 0)
|
if (cols <= 0 || rows <= 0)
|
||||||
cols = rows = 0;
|
cols = rows = 0;
|
||||||
recalculateConsolePosition();
|
recalculateConsolePosition();
|
||||||
m_chat_backend->reformat(cols, rows);
|
m_chat_backend->reformat(cols, rows);
|
||||||
|
|
||||||
|
updateVScrollBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIChatConsole::recalculateConsolePosition()
|
void GUIChatConsole::recalculateConsolePosition()
|
||||||
{
|
{
|
||||||
core::rect<s32> rect(0, 0, m_screensize.X, m_height);
|
core::rect<s32> rect(0, 0, m_screensize.X, m_height);
|
||||||
DesiredRect = rect;
|
DesiredRect = rect;
|
||||||
recalculateAbsolutePosition(false);
|
recalculateAbsolutePosition(true);
|
||||||
|
|
||||||
|
irr::core::rect<s32> scrollbarrect(m_screensize.X - m_scrollbar_width, 0, m_screensize.X, m_height);
|
||||||
|
m_vscrollbar->setRelativePosition(scrollbarrect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIChatConsole::animate(u32 msec)
|
void GUIChatConsole::animate(u32 msec)
|
||||||
@ -253,8 +276,10 @@ void GUIChatConsole::animate(u32 msec)
|
|||||||
// Set invisible if close animation finished (reset by openConsole)
|
// Set invisible if close animation finished (reset by openConsole)
|
||||||
// This function (animate()) is never called once its visibility becomes false so do not
|
// 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
|
// actually set visible to false before the inhibited period is over
|
||||||
if (!m_open && m_height == 0 && m_open_inhibited == 0)
|
if (!m_open && m_height == 0 && m_open_inhibited == 0) {
|
||||||
|
m_vscrollbar->setVisible(false);
|
||||||
IGUIElement::setVisible(false);
|
IGUIElement::setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
if (m_height != goal)
|
if (m_height != goal)
|
||||||
{
|
{
|
||||||
@ -338,6 +363,55 @@ void GUIChatConsole::drawText()
|
|||||||
if (y + line_height < 0)
|
if (y + line_height < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
s32 scroll_pos = buf.getScrollPos();
|
||||||
|
ChatSelection real_mark_begin = m_mark_end > m_mark_begin ? m_mark_begin : m_mark_end;
|
||||||
|
ChatSelection real_mark_end = m_mark_end > m_mark_begin ? m_mark_end : m_mark_begin;
|
||||||
|
if (real_mark_begin != real_mark_end &&
|
||||||
|
(s32)row + scroll_pos >= real_mark_begin.row + real_mark_begin.scroll &&
|
||||||
|
(s32)row + scroll_pos <= real_mark_end.row + real_mark_end.scroll) {
|
||||||
|
ChatFormattedFragment fragment_first = line.fragments[0];
|
||||||
|
|
||||||
|
if ((s32)row + scroll_pos == real_mark_begin.row + real_mark_begin.scroll &&
|
||||||
|
real_mark_begin.fragment < line.fragments.size()) {
|
||||||
|
fragment_first = line.fragments[real_mark_begin.fragment];
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatFormattedFragment fragment_last = line.fragments[line.fragments.size() - 1];
|
||||||
|
|
||||||
|
if ((s32)row + scroll_pos == real_mark_end.row + real_mark_end.scroll &&
|
||||||
|
real_mark_end.fragment < line.fragments.size()) {
|
||||||
|
fragment_last = line.fragments[real_mark_end.fragment];
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 x_begin = (fragment_first.column + 1) * m_fontsize.X;
|
||||||
|
s32 text_size = m_font->getDimension(fragment_last.text.c_str()).Width;
|
||||||
|
s32 x_end = (fragment_last.column + 1) * m_fontsize.X + text_size;
|
||||||
|
|
||||||
|
if ((s32)row + scroll_pos == real_mark_begin.row + real_mark_begin.scroll) {
|
||||||
|
irr::core::stringw text = fragment_first.text.c_str();
|
||||||
|
text = text.subString(0, real_mark_begin.character);
|
||||||
|
s32 text_size = m_font->getDimension(text.c_str()).Width;
|
||||||
|
x_begin = (fragment_first.column + 1) * m_fontsize.X + text_size;
|
||||||
|
|
||||||
|
if (real_mark_begin.x_max)
|
||||||
|
x_begin = x_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((s32)row + scroll_pos == real_mark_end.row + real_mark_end.scroll &&
|
||||||
|
(real_mark_end.character < fragment_last.text.size()) &&
|
||||||
|
!real_mark_end.x_max) {
|
||||||
|
irr::core::stringw text = fragment_last.text.c_str();
|
||||||
|
text = text.subString(0, real_mark_end.character);
|
||||||
|
s32 text_size = m_font->getDimension(text.c_str()).Width;
|
||||||
|
x_end = (fragment_last.column + 1) * m_fontsize.X + text_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
core::rect<s32> destrect(x_begin, y, x_end, y + m_fontsize.Y);
|
||||||
|
video::IVideoDriver* driver = Environment->getVideoDriver();
|
||||||
|
IGUISkin* skin = Environment->getSkin();
|
||||||
|
driver->draw2DRectangle(skin->getColor(EGDC_HIGH_LIGHT), destrect, &AbsoluteClippingRect);
|
||||||
|
}
|
||||||
|
|
||||||
for (const ChatFormattedFragment &fragment : line.fragments) {
|
for (const ChatFormattedFragment &fragment : line.fragments) {
|
||||||
s32 x = (fragment.column + 1) * m_fontsize.X;
|
s32 x = (fragment.column + 1) * m_fontsize.X;
|
||||||
core::rect<s32> destrect(
|
core::rect<s32> destrect(
|
||||||
@ -423,9 +497,166 @@ void GUIChatConsole::drawPrompt()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ChatSelection GUIChatConsole::getCursorPos(s32 x, s32 y)
|
||||||
|
{
|
||||||
|
ChatSelection selection;
|
||||||
|
|
||||||
|
if (m_font == NULL)
|
||||||
|
return selection;
|
||||||
|
|
||||||
|
ChatBuffer& buf = m_chat_backend->getConsoleBuffer();
|
||||||
|
selection.scroll = buf.getScrollPos();
|
||||||
|
selection.initialized = true;
|
||||||
|
|
||||||
|
s32 line_height = m_fontsize.Y;
|
||||||
|
s32 y_min = m_height - m_desired_height;
|
||||||
|
s32 y_max = buf.getRows() * line_height + y_min;
|
||||||
|
|
||||||
|
if (y <= y_min) {
|
||||||
|
selection.row = 0;
|
||||||
|
} else if (y >= y_max) {
|
||||||
|
selection.row = buf.getRows() - 1;
|
||||||
|
} else {
|
||||||
|
for (u32 row = 0; row < buf.getRows(); row++) {
|
||||||
|
s32 y1 = row * line_height + m_height - m_desired_height;
|
||||||
|
s32 y2 = y1 + line_height;
|
||||||
|
|
||||||
|
if (y1 + line_height < 0)
|
||||||
|
return selection;
|
||||||
|
|
||||||
|
if (y >= y1 && y <= y2) {
|
||||||
|
selection.row = row;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatFormattedLine line = buf.getFormattedLine(selection.row);
|
||||||
|
selection.row_buf = line.line_index;
|
||||||
|
int current_row = selection.row;
|
||||||
|
|
||||||
|
while (!line.first) {
|
||||||
|
current_row--;
|
||||||
|
line = buf.getFormattedLine(current_row);
|
||||||
|
selection.line++;
|
||||||
|
}
|
||||||
|
|
||||||
|
line = buf.getFormattedLine(selection.row);
|
||||||
|
|
||||||
|
if (line.fragments.empty())
|
||||||
|
return selection;
|
||||||
|
|
||||||
|
const ChatFormattedFragment &fragment_first = line.fragments[0];
|
||||||
|
const ChatFormattedFragment &fragment_last = line.fragments[line.fragments.size() - 1];
|
||||||
|
s32 x_min = (fragment_first.column + 1) * m_fontsize.X;
|
||||||
|
s32 text_size = m_font->getDimension(fragment_last.text.c_str()).Width;
|
||||||
|
s32 x_max = (fragment_last.column + 1) * m_fontsize.X + text_size;
|
||||||
|
|
||||||
|
if (x < x_min) {
|
||||||
|
x = x_min;
|
||||||
|
} else if (x > x_max) {
|
||||||
|
x = x_max;
|
||||||
|
selection.x_max = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < line.fragments.size(); i++) {
|
||||||
|
const ChatFormattedFragment &fragment = line.fragments[i];
|
||||||
|
s32 fragment_x = (fragment.column + 1) * m_fontsize.X;
|
||||||
|
|
||||||
|
if (x < fragment_x)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (i < line.fragments.size() - 1) {
|
||||||
|
const ChatFormattedFragment &fragment_next = line.fragments[i + 1];
|
||||||
|
s32 fragment_next_x = (fragment_next.column + 1) * m_fontsize.X;
|
||||||
|
|
||||||
|
if (x >= fragment_next_x)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 index = m_font->getCharacterFromPos(fragment.text.c_str(), x - fragment_x);
|
||||||
|
|
||||||
|
selection.fragment = i;
|
||||||
|
selection.character = index > -1 ? index : fragment.text.size() - 1;
|
||||||
|
return selection;
|
||||||
|
}
|
||||||
|
|
||||||
|
return selection;
|
||||||
|
}
|
||||||
|
|
||||||
|
irr::core::stringc GUIChatConsole::getSelectedText()
|
||||||
|
{
|
||||||
|
if (m_font == NULL)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
if (m_mark_begin == m_mark_end)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
bool add_to_string = false;
|
||||||
|
irr::core::stringw text = "";
|
||||||
|
|
||||||
|
ChatSelection real_mark_begin = m_mark_end > m_mark_begin ? m_mark_begin : m_mark_end;
|
||||||
|
ChatSelection real_mark_end = m_mark_end > m_mark_begin ? m_mark_end : m_mark_begin;
|
||||||
|
|
||||||
|
ChatBuffer& buf = m_chat_backend->getConsoleBuffer();
|
||||||
|
|
||||||
|
for (int row = real_mark_begin.row_buf; row < real_mark_end.row_buf + 1; row++) {
|
||||||
|
const ChatLine& line = buf.getLine(row);
|
||||||
|
|
||||||
|
std::vector<ChatFormattedLine> formatted_lines;
|
||||||
|
buf.formatChatLine(line, 0, buf.getColsCount(), formatted_lines);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < formatted_lines.size(); i++) {
|
||||||
|
const ChatFormattedLine &line = formatted_lines[i];
|
||||||
|
|
||||||
|
for (unsigned int j = 0; j < line.fragments.size(); j++) {
|
||||||
|
const ChatFormattedFragment &fragment = line.fragments[j];
|
||||||
|
|
||||||
|
for (unsigned int k = 0; k < fragment.text.size(); k++) {
|
||||||
|
if (!add_to_string &&
|
||||||
|
row == real_mark_begin.row_buf &&
|
||||||
|
i == real_mark_begin.line &&
|
||||||
|
j == real_mark_begin.fragment &&
|
||||||
|
k == real_mark_begin.character) {
|
||||||
|
add_to_string = true;
|
||||||
|
|
||||||
|
if (real_mark_begin.x_max)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (add_to_string) {
|
||||||
|
if (row == real_mark_end.row_buf &&
|
||||||
|
i == real_mark_end.line &&
|
||||||
|
j == real_mark_end.fragment &&
|
||||||
|
k == real_mark_end.character) {
|
||||||
|
if (real_mark_end.x_max)
|
||||||
|
text += fragment.text.c_str()[k];
|
||||||
|
|
||||||
|
irr::core::stringc text_c;
|
||||||
|
text_c = wide_to_utf8(text.c_str()).c_str();
|
||||||
|
return text_c;
|
||||||
|
}
|
||||||
|
|
||||||
|
text += fragment.text.c_str()[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row < real_mark_end.row_buf) {
|
||||||
|
text += L"\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
irr::core::stringc text_c;
|
||||||
|
text_c = wide_to_utf8(text.c_str()).c_str();
|
||||||
|
return text_c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool GUIChatConsole::OnEvent(const SEvent& event)
|
bool GUIChatConsole::OnEvent(const SEvent& event)
|
||||||
{
|
{
|
||||||
|
|
||||||
ChatPrompt &prompt = m_chat_backend->getPrompt();
|
ChatPrompt &prompt = m_chat_backend->getPrompt();
|
||||||
|
|
||||||
if(event.EventType == EET_KEY_INPUT_EVENT && event.KeyInput.PressedDown)
|
if(event.EventType == EET_KEY_INPUT_EVENT && event.KeyInput.PressedDown)
|
||||||
@ -441,7 +672,7 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (event.KeyInput.Key == KEY_ESCAPE || event.KeyInput.Key == KEY_CANCEL) {
|
if (event.KeyInput.Key == KEY_ESCAPE || event.KeyInput.Key == KEY_CANCEL) {
|
||||||
closeConsoleAtOnce();
|
closeConsole();
|
||||||
m_close_on_enter = false;
|
m_close_on_enter = false;
|
||||||
// inhibit open so the_game doesn't reopen immediately
|
// inhibit open so the_game doesn't reopen immediately
|
||||||
m_open_inhibited = 1; // so the ESCAPE button doesn't open the "pause menu"
|
m_open_inhibited = 1; // so the ESCAPE button doesn't open the "pause menu"
|
||||||
@ -449,11 +680,17 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||||||
}
|
}
|
||||||
else if(event.KeyInput.Key == KEY_PRIOR)
|
else if(event.KeyInput.Key == KEY_PRIOR)
|
||||||
{
|
{
|
||||||
|
ChatBuffer& buf = m_chat_backend->getConsoleBuffer();
|
||||||
|
s32 rows = -(s32)buf.getRows();
|
||||||
|
m_vscrollbar->setPos(m_vscrollbar->getPos() + rows);
|
||||||
m_chat_backend->scrollPageUp();
|
m_chat_backend->scrollPageUp();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if(event.KeyInput.Key == KEY_NEXT)
|
else if(event.KeyInput.Key == KEY_NEXT)
|
||||||
{
|
{
|
||||||
|
ChatBuffer& buf = m_chat_backend->getConsoleBuffer();
|
||||||
|
s32 rows = buf.getRows();
|
||||||
|
m_vscrollbar->setPos(m_vscrollbar->getPos() + rows);
|
||||||
m_chat_backend->scrollPageDown();
|
m_chat_backend->scrollPageDown();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -463,7 +700,7 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||||||
std::wstring text = prompt.replace(L"");
|
std::wstring text = prompt.replace(L"");
|
||||||
m_client->typeChatMessage(text);
|
m_client->typeChatMessage(text);
|
||||||
if (m_close_on_enter) {
|
if (m_close_on_enter) {
|
||||||
closeConsoleAtOnce();
|
closeConsole();
|
||||||
m_close_on_enter = false;
|
m_close_on_enter = false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -558,6 +795,12 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||||||
}
|
}
|
||||||
else if(event.KeyInput.Key == KEY_KEY_C && event.KeyInput.Control)
|
else if(event.KeyInput.Key == KEY_KEY_C && event.KeyInput.Control)
|
||||||
{
|
{
|
||||||
|
if (m_mark_begin != m_mark_end) {
|
||||||
|
irr::core::stringc text = getSelectedText();
|
||||||
|
Environment->getOSOperator()->copyToClipboard(text.c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Ctrl-C pressed
|
// Ctrl-C pressed
|
||||||
// Copy text to clipboard
|
// Copy text to clipboard
|
||||||
if (prompt.getCursorLength() <= 0)
|
if (prompt.getCursorLength() <= 0)
|
||||||
@ -649,8 +892,9 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||||||
for (u32 i = 0; i < text.size(); i++)
|
for (u32 i = 0; i < text.size(); i++)
|
||||||
prompt.input(text[i]);
|
prompt.input(text[i]);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else if(event.EventType == EET_MOUSE_INPUT_EVENT)
|
else if(event.EventType == EET_MOUSE_INPUT_EVENT)
|
||||||
@ -659,6 +903,91 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||||||
{
|
{
|
||||||
s32 rows = myround(-3.0 * event.MouseInput.Wheel);
|
s32 rows = myround(-3.0 * event.MouseInput.Wheel);
|
||||||
m_chat_backend->scroll(rows);
|
m_chat_backend->scroll(rows);
|
||||||
|
m_vscrollbar->setPos(m_vscrollbar->getPos() + rows);
|
||||||
|
} else if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) {
|
||||||
|
m_mouse_marking = true;
|
||||||
|
m_mark_begin = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
|
||||||
|
m_mark_end = m_mark_begin;
|
||||||
|
} else if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP) {
|
||||||
|
if (m_mouse_marking) {
|
||||||
|
m_mark_end = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
|
||||||
|
m_mouse_marking = false;
|
||||||
|
|
||||||
|
if (m_mark_begin == m_mark_end) {
|
||||||
|
m_mark_begin.reset();
|
||||||
|
m_mark_end.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (event.MouseInput.Event == EMIE_MOUSE_MOVED) {
|
||||||
|
if (m_mouse_marking) {
|
||||||
|
m_mark_end = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#ifdef HAVE_TOUCHSCREENGUI
|
||||||
|
else if (event.EventType == EET_TOUCH_INPUT_EVENT) {
|
||||||
|
if (event.TouchInput.Event == irr::ETIE_PRESSED_DOWN) {
|
||||||
|
m_mouse_marking = false;
|
||||||
|
m_long_press = false;
|
||||||
|
m_cursor_press_pos = getCursorPos(event.TouchInput.X, event.TouchInput.Y);
|
||||||
|
|
||||||
|
ChatSelection real_mark_begin = m_mark_end > m_mark_begin ? m_mark_begin : m_mark_end;
|
||||||
|
ChatSelection real_mark_end = m_mark_end > m_mark_begin ? m_mark_end : m_mark_begin;
|
||||||
|
|
||||||
|
if (m_cursor_press_pos < real_mark_begin || m_cursor_press_pos > real_mark_end) {
|
||||||
|
m_mark_begin = m_cursor_press_pos;
|
||||||
|
m_mark_end = m_cursor_press_pos;
|
||||||
|
m_mouse_marking = true;
|
||||||
|
}
|
||||||
|
} else if (event.TouchInput.Event == irr::ETIE_LEFT_UP) {
|
||||||
|
ChatSelection cursor_pos = getCursorPos(event.TouchInput.X, event.TouchInput.Y);
|
||||||
|
|
||||||
|
if (!m_long_press && m_cursor_press_pos == cursor_pos) {
|
||||||
|
m_mark_begin.reset();
|
||||||
|
m_mark_end.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_cursor_press_pos.reset();
|
||||||
|
m_mouse_marking = false;
|
||||||
|
m_long_press = false;
|
||||||
|
} else if (event.TouchInput.Event == irr::ETIE_MOVED) {
|
||||||
|
ChatSelection cursor_pos = getCursorPos(event.TouchInput.X, event.TouchInput.Y);
|
||||||
|
|
||||||
|
if (!m_mouse_marking && !m_long_press && m_cursor_press_pos.initialized &&
|
||||||
|
m_cursor_press_pos != cursor_pos) {
|
||||||
|
m_mark_begin = m_cursor_press_pos;
|
||||||
|
m_mark_end = m_cursor_press_pos;
|
||||||
|
m_mouse_marking = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_mouse_marking) {
|
||||||
|
m_mark_end = cursor_pos;
|
||||||
|
}
|
||||||
|
} else if (event.TouchInput.Event == irr::ETIE_PRESSED_LONG) {
|
||||||
|
if (!m_mouse_marking) {
|
||||||
|
m_long_press = true;
|
||||||
|
if (m_mark_begin != m_mark_end) {
|
||||||
|
irr::core::stringc text = getSelectedText();
|
||||||
|
Environment->getOSOperator()->copyToClipboard(text.c_str());
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
SDL_AndroidShowToast(
|
||||||
|
"Copied to clipboard", 2,
|
||||||
|
-1, 0, 0);
|
||||||
|
#elif __IOS__
|
||||||
|
porting::showToast("Copied to clipboard");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else if (event.EventType == EET_GUI_EVENT) {
|
||||||
|
if (event.GUIEvent.EventType == EGET_SCROLL_BAR_CHANGED) {
|
||||||
|
updateVScrollBar();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -669,9 +998,174 @@ void GUIChatConsole::setVisible(bool visible)
|
|||||||
{
|
{
|
||||||
m_open = visible;
|
m_open = visible;
|
||||||
IGUIElement::setVisible(visible);
|
IGUIElement::setVisible(visible);
|
||||||
|
m_vscrollbar->setVisible(visible);
|
||||||
if (!visible) {
|
if (!visible) {
|
||||||
m_height = 0;
|
m_height = 0;
|
||||||
recalculateConsolePosition();
|
recalculateConsolePosition();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! create a vertical scroll bar
|
||||||
|
void GUIChatConsole::createVScrollBar()
|
||||||
|
{
|
||||||
|
IGUISkin *skin = 0;
|
||||||
|
if (Environment)
|
||||||
|
skin = Environment->getSkin();
|
||||||
|
|
||||||
|
m_scrollbar_width = skin ? skin->getSize(gui::EGDS_SCROLLBAR_SIZE) : 16;
|
||||||
|
m_scrollbar_width *= 2;
|
||||||
|
|
||||||
|
irr::core::rect<s32> scrollbarrect(m_screensize.X - m_scrollbar_width,
|
||||||
|
0, m_screensize.X, m_height);
|
||||||
|
m_vscrollbar = new GUIScrollBar(Environment, getParent(), -1,
|
||||||
|
scrollbarrect, false, true);
|
||||||
|
|
||||||
|
m_vscrollbar->setVisible(false);
|
||||||
|
m_vscrollbar->setMax(0);
|
||||||
|
m_vscrollbar->setPos(0);
|
||||||
|
m_vscrollbar->setPageSize(0);
|
||||||
|
m_vscrollbar->setSmallStep(1);
|
||||||
|
m_vscrollbar->setLargeStep(1);
|
||||||
|
m_vscrollbar->setArrowsVisible(GUIScrollBar::ArrowVisibility::SHOW);
|
||||||
|
|
||||||
|
ITextureSource *tsrc = m_client->getTextureSource();
|
||||||
|
m_vscrollbar->setTextures({
|
||||||
|
tsrc->getTexture("gui/scrollbar_bg.png"),
|
||||||
|
tsrc->getTexture("gui/scrollbar_slider_long.png"),
|
||||||
|
tsrc->getTexture("gui/scrollbar_up.png"),
|
||||||
|
tsrc->getTexture("gui/scrollbar_down.png"),
|
||||||
|
});
|
||||||
|
|
||||||
|
addChild(m_vscrollbar);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GUIChatConsole::updateVScrollBar()
|
||||||
|
{
|
||||||
|
if (!m_vscrollbar)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ChatBuffer& buf = m_chat_backend->getConsoleBuffer();
|
||||||
|
|
||||||
|
if (m_bottom_scroll_pos != buf.getBottomScrollPos()) {
|
||||||
|
m_bottom_scroll_pos = buf.getBottomScrollPos();
|
||||||
|
|
||||||
|
if (buf.getBottomScrollPos() > 0) {
|
||||||
|
buf.scrollAbsolute(m_bottom_scroll_pos);
|
||||||
|
m_vscrollbar->setMax(m_bottom_scroll_pos);
|
||||||
|
m_vscrollbar->setPos(m_bottom_scroll_pos);
|
||||||
|
} else {
|
||||||
|
m_vscrollbar->setMax(0);
|
||||||
|
m_vscrollbar->setPos(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 page_size = (m_bottom_scroll_pos + buf.getRows() + 1) * m_fontsize.Y;
|
||||||
|
if (m_vscrollbar->getPageSize() != page_size) {
|
||||||
|
m_vscrollbar->setPageSize(page_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_vscrollbar->getPos() != buf.getScrollPos()) {
|
||||||
|
if (buf.getScrollPos() >= 0) {
|
||||||
|
s32 deltaScrollY = m_vscrollbar->getPos() - buf.getScrollPos();
|
||||||
|
m_chat_backend->scroll(deltaScrollY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsVisible) {
|
||||||
|
if (m_vscrollbar->isVisible() && m_vscrollbar->getMax() == 0)
|
||||||
|
m_vscrollbar->setVisible(false);
|
||||||
|
else if (!m_vscrollbar->isVisible() && m_vscrollbar->getMax() > 0)
|
||||||
|
m_vscrollbar->setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GUIChatConsole::hasFocus()
|
||||||
|
{
|
||||||
|
if (Environment->hasFocus(this))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (Environment->hasFocus(m_vscrollbar))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const core::list<gui::IGUIElement*> &children = m_vscrollbar->getChildren();
|
||||||
|
|
||||||
|
for (gui::IGUIElement *it : children) {
|
||||||
|
if (Environment->hasFocus(it))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GUIChatConsole::convertToMouseEvent(
|
||||||
|
SEvent &mouse_event, SEvent touch_event) const noexcept
|
||||||
|
{
|
||||||
|
#ifdef HAVE_TOUCHSCREENGUI
|
||||||
|
mouse_event = {};
|
||||||
|
mouse_event.EventType = EET_MOUSE_INPUT_EVENT;
|
||||||
|
mouse_event.MouseInput.X = touch_event.TouchInput.X;
|
||||||
|
mouse_event.MouseInput.Y = touch_event.TouchInput.Y;
|
||||||
|
switch (touch_event.TouchInput.Event) {
|
||||||
|
case ETIE_PRESSED_DOWN:
|
||||||
|
mouse_event.MouseInput.Event = EMIE_LMOUSE_PRESSED_DOWN;
|
||||||
|
mouse_event.MouseInput.ButtonStates = EMBSM_LEFT;
|
||||||
|
break;
|
||||||
|
case ETIE_MOVED:
|
||||||
|
mouse_event.MouseInput.Event = EMIE_MOUSE_MOVED;
|
||||||
|
mouse_event.MouseInput.ButtonStates = EMBSM_LEFT;
|
||||||
|
break;
|
||||||
|
case ETIE_LEFT_UP:
|
||||||
|
mouse_event.MouseInput.Event = EMIE_LMOUSE_LEFT_UP;
|
||||||
|
mouse_event.MouseInput.ButtonStates = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GUIChatConsole::preprocessEvent(SEvent event)
|
||||||
|
{
|
||||||
|
updateVScrollBar();
|
||||||
|
|
||||||
|
#ifdef HAVE_TOUCHSCREENGUI
|
||||||
|
if (event.EventType == irr::EET_TOUCH_INPUT_EVENT) {
|
||||||
|
const core::position2di p(event.TouchInput.X, event.TouchInput.Y);
|
||||||
|
|
||||||
|
u32 row = m_chat_backend->getConsoleBuffer().getRows();
|
||||||
|
s32 prompt_y = row * m_fontsize.Y + m_height - m_desired_height;
|
||||||
|
|
||||||
|
if (m_vscrollbar->isPointInside(p) || !isPointInside(p)) {
|
||||||
|
SEvent mouse_event = {};
|
||||||
|
bool success = convertToMouseEvent(mouse_event, event);
|
||||||
|
if (success) {
|
||||||
|
Environment->postEventFromUser(mouse_event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if defined(__ANDROID__) || defined(__IOS__)
|
||||||
|
else if (!porting::hasRealKeyboard() &&
|
||||||
|
event.TouchInput.Y >= prompt_y &&
|
||||||
|
event.TouchInput.Y <= m_height) {
|
||||||
|
if (event.TouchInput.Event == ETIE_PRESSED_DOWN &&
|
||||||
|
!m_android_chat_open) {
|
||||||
|
ChatPrompt& prompt = m_chat_backend->getPrompt();
|
||||||
|
porting::showInputDialog("", "", 2);
|
||||||
|
m_android_chat_open = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else {
|
||||||
|
OnEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@ -23,6 +23,75 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "modalMenu.h"
|
#include "modalMenu.h"
|
||||||
#include "chat.h"
|
#include "chat.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "guiScrollBar.h"
|
||||||
|
|
||||||
|
struct ChatSelection
|
||||||
|
{
|
||||||
|
ChatSelection() : initialized(false), scroll(0), row(0), row_buf(0),
|
||||||
|
line(0), fragment(0), character(0), x_max(false) {};
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
initialized = false;
|
||||||
|
scroll = 0;
|
||||||
|
row = 0;
|
||||||
|
row_buf = 0;
|
||||||
|
line = 0;
|
||||||
|
fragment = 0;
|
||||||
|
character = 0;
|
||||||
|
x_max = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator== (const ChatSelection &other) const {
|
||||||
|
return (row + scroll == other.row + other.scroll &&
|
||||||
|
row_buf == other.row_buf &&
|
||||||
|
line == other.line &&
|
||||||
|
fragment == other.fragment &&
|
||||||
|
character == other.character &&
|
||||||
|
x_max == other.x_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator< (const ChatSelection &other) const {
|
||||||
|
if (row + scroll != other.row + other.scroll)
|
||||||
|
return (row + scroll < other.row + other.scroll);
|
||||||
|
if (row_buf != other.row_buf)
|
||||||
|
return (row_buf < other.row_buf);
|
||||||
|
if (line != other.line)
|
||||||
|
return (line < other.line);
|
||||||
|
if (fragment != other.fragment)
|
||||||
|
return (fragment < other.fragment);
|
||||||
|
if (character != other.character)
|
||||||
|
return (character < other.character);
|
||||||
|
if (x_max != other.x_max)
|
||||||
|
return (x_max < other.x_max);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator> (const ChatSelection &other) {
|
||||||
|
return other < *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<= (const ChatSelection &other) {
|
||||||
|
return !(*this > other);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator>= (const ChatSelection &other) {
|
||||||
|
return !(*this < other);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!= (const ChatSelection &other) const {
|
||||||
|
return !this->operator==(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool initialized;
|
||||||
|
int scroll;
|
||||||
|
int row;
|
||||||
|
int row_buf;
|
||||||
|
unsigned int line;
|
||||||
|
unsigned int fragment;
|
||||||
|
unsigned int character;
|
||||||
|
bool x_max;
|
||||||
|
};
|
||||||
|
|
||||||
class Client;
|
class Client;
|
||||||
|
|
||||||
@ -50,8 +119,6 @@ public:
|
|||||||
// Close the console, equivalent to openConsole(0).
|
// Close the console, equivalent to openConsole(0).
|
||||||
// This doesn't close immediately but initiates an animation.
|
// This doesn't close immediately but initiates an animation.
|
||||||
void closeConsole();
|
void closeConsole();
|
||||||
// Close the console immediately, without animation.
|
|
||||||
void closeConsoleAtOnce();
|
|
||||||
// Set whether to close the console after the user presses enter.
|
// Set whether to close the console after the user presses enter.
|
||||||
void setCloseOnEnter(bool close) { m_close_on_enter = close; }
|
void setCloseOnEnter(bool close) { m_close_on_enter = close; }
|
||||||
|
|
||||||
@ -72,6 +139,18 @@ public:
|
|||||||
|
|
||||||
virtual void setVisible(bool visible);
|
virtual void setVisible(bool visible);
|
||||||
|
|
||||||
|
bool hasFocus();
|
||||||
|
|
||||||
|
bool convertToMouseEvent(
|
||||||
|
SEvent &mouse_event, SEvent touch_event) const noexcept;
|
||||||
|
|
||||||
|
bool preprocessEvent(SEvent event);
|
||||||
|
|
||||||
|
bool getAndroidChatOpen() { return m_android_chat_open; }
|
||||||
|
void setAndroidChatOpen(bool value) { m_android_chat_open = value; }
|
||||||
|
|
||||||
|
static GUIChatConsole* getChatConsole() { return m_chat_console; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void reformatConsole();
|
void reformatConsole();
|
||||||
void recalculateConsolePosition();
|
void recalculateConsolePosition();
|
||||||
@ -82,7 +161,14 @@ private:
|
|||||||
void drawText();
|
void drawText();
|
||||||
void drawPrompt();
|
void drawPrompt();
|
||||||
|
|
||||||
|
ChatSelection getCursorPos(s32 x, s32 y);
|
||||||
|
irr::core::stringc getSelectedText();
|
||||||
|
void createVScrollBar();
|
||||||
|
void updateVScrollBar();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static GUIChatConsole* m_chat_console;
|
||||||
|
|
||||||
ChatBackend* m_chat_backend;
|
ChatBackend* m_chat_backend;
|
||||||
Client* m_client;
|
Client* m_client;
|
||||||
IMenuManager* m_menumgr;
|
IMenuManager* m_menumgr;
|
||||||
@ -124,4 +210,16 @@ private:
|
|||||||
// font
|
// font
|
||||||
gui::IGUIFont *m_font = nullptr;
|
gui::IGUIFont *m_font = nullptr;
|
||||||
v2u32 m_fontsize;
|
v2u32 m_fontsize;
|
||||||
|
|
||||||
|
ChatSelection m_mark_begin;
|
||||||
|
ChatSelection m_mark_end;
|
||||||
|
bool m_mouse_marking = false;
|
||||||
|
bool m_long_press = false;
|
||||||
|
ChatSelection m_cursor_press_pos;
|
||||||
|
|
||||||
|
u32 m_scrollbar_width = 0;
|
||||||
|
GUIScrollBar *m_vscrollbar = nullptr;
|
||||||
|
s32 m_bottom_scroll_pos = 0;
|
||||||
|
|
||||||
|
bool m_android_chat_open = false;
|
||||||
};
|
};
|
||||||
|
@ -17,11 +17,12 @@ the arrow buttons where there is insufficient space.
|
|||||||
GUIScrollBar::GUIScrollBar(IGUIEnvironment *environment, IGUIElement *parent, s32 id,
|
GUIScrollBar::GUIScrollBar(IGUIEnvironment *environment, IGUIElement *parent, s32 id,
|
||||||
core::rect<s32> rectangle, bool horizontal, bool auto_scale) :
|
core::rect<s32> rectangle, bool horizontal, bool auto_scale) :
|
||||||
IGUIElement(EGUIET_ELEMENT, environment, parent, id, rectangle),
|
IGUIElement(EGUIET_ELEMENT, environment, parent, id, rectangle),
|
||||||
up_button(nullptr), down_button(nullptr), is_dragging(false),
|
up_button(nullptr), down_button(nullptr), bg_image(nullptr),
|
||||||
is_horizontal(horizontal), is_auto_scaling(auto_scale),
|
slider_image(nullptr), is_dragging(false), is_horizontal(horizontal),
|
||||||
dragged_by_slider(false), tray_clicked(false), scroll_pos(0),
|
is_auto_scaling(auto_scale), dragged_by_slider(false),
|
||||||
draw_center(0), thumb_size(0), min_pos(0), max_pos(100), small_step(10),
|
tray_clicked(false), scroll_pos(0), draw_center(0), thumb_size(0),
|
||||||
large_step(50), drag_offset(0), page_size(100), border_size(0)
|
min_pos(0), max_pos(100), small_step(10), large_step(50),
|
||||||
|
drag_offset(0), page_size(100), border_size(0)
|
||||||
{
|
{
|
||||||
refreshControls();
|
refreshControls();
|
||||||
setNotClipped(false);
|
setNotClipped(false);
|
||||||
@ -217,9 +218,13 @@ void GUIScrollBar::draw()
|
|||||||
if (is_horizontal)
|
if (is_horizontal)
|
||||||
rect = {h, 0, w - h, h};
|
rect = {h, 0, w - h, h};
|
||||||
|
|
||||||
gui::IGUIImage *e = Environment->addImage(rect, this);
|
if (!bg_image) {
|
||||||
e->setImage(m_textures[0]);
|
bg_image = Environment->addImage(rect, this);
|
||||||
e->setScaleImage(true);
|
bg_image->setImage(m_textures[0]);
|
||||||
|
bg_image->setScaleImage(true);
|
||||||
|
} else {
|
||||||
|
bg_image->setRelativePosition(rect);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
skin->draw2DRectangle(this, skin->getColor(EGDC_SCROLLBAR),
|
skin->draw2DRectangle(this, skin->getColor(EGDC_SCROLLBAR),
|
||||||
slider_rect, &AbsoluteClippingRect);
|
slider_rect, &AbsoluteClippingRect);
|
||||||
@ -247,9 +252,13 @@ void GUIScrollBar::draw()
|
|||||||
if (is_horizontal)
|
if (is_horizontal)
|
||||||
rect = {draw_center - (w / 2), 0, draw_center + w - (w / 2), h};
|
rect = {draw_center - (w / 2), 0, draw_center + w - (w / 2), h};
|
||||||
|
|
||||||
gui::IGUIImage *e = Environment->addImage(core::rect<s32>(rect), this);
|
if (!slider_image) {
|
||||||
e->setImage(m_textures[1]);
|
slider_image = Environment->addImage(core::rect<s32>(rect), this);
|
||||||
e->setScaleImage(true);
|
slider_image->setImage(m_textures[1]);
|
||||||
|
slider_image->setScaleImage(true);
|
||||||
|
} else {
|
||||||
|
slider_image->setRelativePosition(rect);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
skin->draw3DButtonPaneStandard(this, slider_rect, &AbsoluteClippingRect);
|
skin->draw3DButtonPaneStandard(this, slider_rect, &AbsoluteClippingRect);
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ public:
|
|||||||
s32 getLargeStep() const { return large_step; }
|
s32 getLargeStep() const { return large_step; }
|
||||||
s32 getSmallStep() const { return small_step; }
|
s32 getSmallStep() const { return small_step; }
|
||||||
s32 getPos() const;
|
s32 getPos() const;
|
||||||
|
s32 getPageSize() const { return page_size; }
|
||||||
|
|
||||||
void setMax(const s32 &max);
|
void setMax(const s32 &max);
|
||||||
void setMin(const s32 &min);
|
void setMin(const s32 &min);
|
||||||
@ -57,6 +58,8 @@ private:
|
|||||||
|
|
||||||
IGUIButton *up_button;
|
IGUIButton *up_button;
|
||||||
IGUIButton *down_button;
|
IGUIButton *down_button;
|
||||||
|
gui::IGUIImage *bg_image;
|
||||||
|
gui::IGUIImage *slider_image;
|
||||||
ArrowVisibility arrow_visibility = DEFAULT;
|
ArrowVisibility arrow_visibility = DEFAULT;
|
||||||
bool is_dragging;
|
bool is_dragging;
|
||||||
bool is_horizontal;
|
bool is_horizontal;
|
||||||
|
BIN
textures/base/pack/gui/scrollbar_bg.png
Normal file
BIN
textures/base/pack/gui/scrollbar_bg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 78 B |
BIN
textures/base/pack/gui/scrollbar_down.png
Normal file
BIN
textures/base/pack/gui/scrollbar_down.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 480 B |
BIN
textures/base/pack/gui/scrollbar_slider_long.png
Normal file
BIN
textures/base/pack/gui/scrollbar_slider_long.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 425 B |
BIN
textures/base/pack/gui/scrollbar_up.png
Normal file
BIN
textures/base/pack/gui/scrollbar_up.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 487 B |
Loading…
x
Reference in New Issue
Block a user