Chat console fixes (#133)
* Some fixes for text selection in chat. - Reset selection on chat open - Reset selection on new message - Reset selection when window size changed * Don't move to bottom when user is scrolling chat * Some work on prompt selection * Make it working when text length is larger than max visible length * Handle touch events for prompt * Avoid moving chat history on new messages during scrolling. Also simplify selection marks comparing. * Move scroll to bottom on sending new message when console is opened without close on enter * Fixed copy to clipboard when chat buffer is full and also keep text selected when new message arrives * Some improvements for prompt selection * Delete selected text on new input or backspace key press * Fixed text selection and cursor pos for regular font * Fixed drawing prompt with newlines * Fixed empty prompt selection with ctrl+a * Enable chat console on android tablets
This commit is contained in:
parent
0de69ddffb
commit
7e7420c5e7
39
src/chat.cpp
39
src/chat.cpp
@ -42,13 +42,14 @@ void ChatBuffer::addLine(const std::wstring &name, const std::wstring &text)
|
|||||||
{
|
{
|
||||||
m_lines_modified = true;
|
m_lines_modified = true;
|
||||||
|
|
||||||
ChatLine line(name, text);
|
ChatLine line(name, text, m_current_line_index);
|
||||||
m_unformatted.push_back(line);
|
m_unformatted.push_back(line);
|
||||||
|
m_current_line_index++;
|
||||||
|
|
||||||
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_unformatted.size() - 1, m_cols, m_formatted);
|
u32 num_added = formatChatLine(line, m_cols, m_formatted);
|
||||||
if (scrolled_at_bottom)
|
if (scrolled_at_bottom)
|
||||||
m_scroll += num_added;
|
m_scroll += num_added;
|
||||||
}
|
}
|
||||||
@ -63,6 +64,7 @@ void ChatBuffer::clear()
|
|||||||
{
|
{
|
||||||
m_unformatted.clear();
|
m_unformatted.clear();
|
||||||
m_formatted.clear();
|
m_formatted.clear();
|
||||||
|
m_current_line_index = 0;
|
||||||
m_scroll = 0;
|
m_scroll = 0;
|
||||||
m_lines_modified = true;
|
m_lines_modified = true;
|
||||||
}
|
}
|
||||||
@ -117,6 +119,8 @@ void ChatBuffer::deleteOldest(u32 count)
|
|||||||
m_scroll = getBottomScrollPos();
|
m_scroll = getBottomScrollPos();
|
||||||
else
|
else
|
||||||
scrollAbsolute(m_scroll - del_formatted);
|
scrollAbsolute(m_scroll - del_formatted);
|
||||||
|
|
||||||
|
m_del_formatted += del_formatted;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatBuffer::deleteByAge(f32 maxAge)
|
void ChatBuffer::deleteByAge(f32 maxAge)
|
||||||
@ -173,7 +177,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], i, cols, m_formatted);
|
formatChatLine(m_unformatted[i], cols, m_formatted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,7 +228,7 @@ void ChatBuffer::scrollBottom()
|
|||||||
m_scroll = getBottomScrollPos();
|
m_scroll = getBottomScrollPos();
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 ChatBuffer::formatChatLine(const ChatLine& line, int line_index, u32 cols,
|
u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols,
|
||||||
std::vector<ChatFormattedLine>& destination) const
|
std::vector<ChatFormattedLine>& destination) const
|
||||||
{
|
{
|
||||||
u32 num_added = 0;
|
u32 num_added = 0;
|
||||||
@ -267,7 +271,7 @@ u32 ChatBuffer::formatChatLine(const ChatLine& line, int line_index, 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;
|
next_line.line_index = line.line_index;
|
||||||
bool text_processing = false;
|
bool text_processing = false;
|
||||||
|
|
||||||
// Produce fragments and layout them into lines
|
// Produce fragments and layout them into lines
|
||||||
@ -391,6 +395,7 @@ void ChatPrompt::input(wchar_t ch)
|
|||||||
clampView();
|
clampView();
|
||||||
m_nick_completion_start = 0;
|
m_nick_completion_start = 0;
|
||||||
m_nick_completion_end = 0;
|
m_nick_completion_end = 0;
|
||||||
|
m_line_modified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatPrompt::input(const std::wstring &str)
|
void ChatPrompt::input(const std::wstring &str)
|
||||||
@ -400,6 +405,7 @@ void ChatPrompt::input(const std::wstring &str)
|
|||||||
clampView();
|
clampView();
|
||||||
m_nick_completion_start = 0;
|
m_nick_completion_start = 0;
|
||||||
m_nick_completion_end = 0;
|
m_nick_completion_end = 0;
|
||||||
|
m_line_modified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatPrompt::addToHistory(const std::wstring &line)
|
void ChatPrompt::addToHistory(const std::wstring &line)
|
||||||
@ -424,6 +430,7 @@ void ChatPrompt::clear()
|
|||||||
m_cursor = 0;
|
m_cursor = 0;
|
||||||
m_nick_completion_start = 0;
|
m_nick_completion_start = 0;
|
||||||
m_nick_completion_end = 0;
|
m_nick_completion_end = 0;
|
||||||
|
m_line_modified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring ChatPrompt::replace(const std::wstring &line)
|
std::wstring ChatPrompt::replace(const std::wstring &line)
|
||||||
@ -434,6 +441,7 @@ std::wstring ChatPrompt::replace(const std::wstring &line)
|
|||||||
clampView();
|
clampView();
|
||||||
m_nick_completion_start = 0;
|
m_nick_completion_start = 0;
|
||||||
m_nick_completion_end = 0;
|
m_nick_completion_end = 0;
|
||||||
|
m_line_modified = true;
|
||||||
return old_line;
|
return old_line;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -535,6 +543,7 @@ void ChatPrompt::nickCompletion(const std::list<std::string>& names, bool backwa
|
|||||||
clampView();
|
clampView();
|
||||||
m_nick_completion_start = prefix_start;
|
m_nick_completion_start = prefix_start;
|
||||||
m_nick_completion_end = prefix_end;
|
m_nick_completion_end = prefix_end;
|
||||||
|
m_line_modified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatPrompt::reformat(u32 cols)
|
void ChatPrompt::reformat(u32 cols)
|
||||||
@ -616,6 +625,7 @@ void ChatPrompt::cursorOperation(CursorOp op, CursorOpDir dir, CursorOpScope sco
|
|||||||
m_line.erase(m_cursor, abs(new_cursor - old_cursor));
|
m_line.erase(m_cursor, abs(new_cursor - old_cursor));
|
||||||
}
|
}
|
||||||
m_cursor_len = 0;
|
m_cursor_len = 0;
|
||||||
|
m_line_modified = true;
|
||||||
break;
|
break;
|
||||||
case CURSOROP_SELECT:
|
case CURSOROP_SELECT:
|
||||||
if (scope == CURSOROP_SCOPE_LINE) {
|
if (scope == CURSOROP_SCOPE_LINE) {
|
||||||
@ -635,6 +645,25 @@ void ChatPrompt::cursorOperation(CursorOp op, CursorOpDir dir, CursorOpScope sco
|
|||||||
m_nick_completion_end = 0;
|
m_nick_completion_end = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChatPrompt::setCursorPos(int cursor_pos)
|
||||||
|
{
|
||||||
|
s32 length = m_line.size();
|
||||||
|
m_cursor = MYMAX(MYMIN(cursor_pos, length), 0);
|
||||||
|
m_cursor_len = 0;
|
||||||
|
|
||||||
|
clampView();
|
||||||
|
|
||||||
|
m_nick_completion_start = 0;
|
||||||
|
m_nick_completion_end = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatPrompt::setViewPosition(int view)
|
||||||
|
{
|
||||||
|
m_view = view;
|
||||||
|
|
||||||
|
clampView();
|
||||||
|
}
|
||||||
|
|
||||||
void ChatPrompt::clampView()
|
void ChatPrompt::clampView()
|
||||||
{
|
{
|
||||||
s32 length = m_line.size();
|
s32 length = m_line.size();
|
||||||
|
37
src/chat.h
37
src/chat.h
@ -37,16 +37,22 @@ struct ChatLine
|
|||||||
EnrichedString name;
|
EnrichedString name;
|
||||||
// message text
|
// message text
|
||||||
EnrichedString text;
|
EnrichedString text;
|
||||||
|
// Line index in ChatLine buffer
|
||||||
|
int line_index;
|
||||||
|
|
||||||
ChatLine(const std::wstring &a_name, const std::wstring &a_text):
|
ChatLine(const std::wstring &a_name, const std::wstring &a_text,
|
||||||
|
int a_line_index):
|
||||||
name(a_name),
|
name(a_name),
|
||||||
text(a_text)
|
text(a_text),
|
||||||
|
line_index(a_line_index)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatLine(const EnrichedString &a_name, const EnrichedString &a_text):
|
ChatLine(const EnrichedString &a_name, const EnrichedString &a_text,
|
||||||
|
int a_line_index):
|
||||||
name(a_name),
|
name(a_name),
|
||||||
text(a_text)
|
text(a_text),
|
||||||
|
line_index(a_line_index)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -123,10 +129,13 @@ public:
|
|||||||
bool getLinesModified() const { return m_lines_modified; }
|
bool getLinesModified() const { return m_lines_modified; }
|
||||||
void resetLinesModified() { m_lines_modified = false; }
|
void resetLinesModified() { m_lines_modified = false; }
|
||||||
|
|
||||||
|
u32 getDelFormatted() const { return m_del_formatted; }
|
||||||
|
void resetDelFormatted() { m_del_formatted = 0; }
|
||||||
|
|
||||||
// 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, int line_index, u32 cols,
|
u32 formatChatLine(const ChatLine& line, u32 cols,
|
||||||
std::vector<ChatFormattedLine>& destination) const;
|
std::vector<ChatFormattedLine>& destination) const;
|
||||||
|
|
||||||
void resize(u32 scrollback);
|
void resize(u32 scrollback);
|
||||||
@ -155,6 +164,11 @@ private:
|
|||||||
// Is always set to true when m_unformatted is modified, because that's what
|
// Is always set to true when m_unformatted is modified, because that's what
|
||||||
// determines the output of getLineCount() and getLine()
|
// determines the output of getLineCount() and getLine()
|
||||||
bool m_lines_modified = true;
|
bool m_lines_modified = true;
|
||||||
|
|
||||||
|
// How many formatted lines have been deleted
|
||||||
|
u32 m_del_formatted = 0;
|
||||||
|
|
||||||
|
int m_current_line_index = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ChatPrompt
|
class ChatPrompt
|
||||||
@ -196,6 +210,8 @@ public:
|
|||||||
std::wstring getVisiblePortion() const;
|
std::wstring getVisiblePortion() const;
|
||||||
// Get cursor position (relative to visible portion). -1 if invalid
|
// Get cursor position (relative to visible portion). -1 if invalid
|
||||||
s32 getVisibleCursorPosition() const;
|
s32 getVisibleCursorPosition() const;
|
||||||
|
// Get view position (absolute value)
|
||||||
|
s32 getViewPosition() const { return m_view; }
|
||||||
// Get length of cursor selection
|
// Get length of cursor selection
|
||||||
s32 getCursorLength() const { return m_cursor_len; }
|
s32 getCursorLength() const { return m_cursor_len; }
|
||||||
|
|
||||||
@ -231,6 +247,14 @@ public:
|
|||||||
// deletes the word to the left of the cursor.
|
// deletes the word to the left of the cursor.
|
||||||
void cursorOperation(CursorOp op, CursorOpDir dir, CursorOpScope scope);
|
void cursorOperation(CursorOp op, CursorOpDir dir, CursorOpScope scope);
|
||||||
|
|
||||||
|
void setCursorPos(int cursor_pos);
|
||||||
|
void setViewPosition(int view);
|
||||||
|
|
||||||
|
// Functions for keeping track of whether the line was modified by any
|
||||||
|
// preceding operations
|
||||||
|
bool getLineModified() const { return m_line_modified; }
|
||||||
|
void resetLineModified() { m_line_modified = false; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// set m_view to ensure that 0 <= m_view <= m_cursor < m_view + m_cols
|
// set m_view to ensure that 0 <= m_view <= m_cursor < m_view + m_cols
|
||||||
// if line can be fully shown, set m_view to zero
|
// if line can be fully shown, set m_view to zero
|
||||||
@ -262,6 +286,9 @@ private:
|
|||||||
s32 m_nick_completion_start = 0;
|
s32 m_nick_completion_start = 0;
|
||||||
// Last nick completion start (index into m_line)
|
// Last nick completion start (index into m_line)
|
||||||
s32 m_nick_completion_end = 0;
|
s32 m_nick_completion_end = 0;
|
||||||
|
|
||||||
|
// True if line was modified
|
||||||
|
bool m_line_modified = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ChatBackend
|
class ChatBackend
|
||||||
|
@ -2141,13 +2141,11 @@ void Game::openConsole(float scale, const wchar_t *line)
|
|||||||
porting::showInputDialog("", "", 2);
|
porting::showInputDialog("", "", 2);
|
||||||
gui_chat_console->setAndroidChatOpen(true);
|
gui_chat_console->setAndroidChatOpen(true);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
#if defined(__ANDROID__)
|
|
||||||
return;
|
|
||||||
#elif defined(__IOS__)
|
|
||||||
if (!g_settings->getBool("device_is_tablet"))
|
if (!g_settings->getBool("device_is_tablet"))
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (gui_chat_console->isOpenInhibited())
|
if (gui_chat_console->isOpenInhibited())
|
||||||
return;
|
return;
|
||||||
gui_chat_console->openConsole(scale);
|
gui_chat_console->openConsole(scale);
|
||||||
@ -2986,6 +2984,13 @@ void Game::updateChat(f32 dtime)
|
|||||||
if (buf.getLinesModified()) {
|
if (buf.getLinesModified()) {
|
||||||
buf.resetLinesModified();
|
buf.resetLinesModified();
|
||||||
m_game_ui->setChatText(chat_backend->getRecentChat(), buf.getLineCount());
|
m_game_ui->setChatText(chat_backend->getRecentChat(), buf.getLineCount());
|
||||||
|
gui_chat_console->onLinesModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &prompt = chat_backend->getPrompt();
|
||||||
|
if (prompt.getLineModified()) {
|
||||||
|
prompt.resetLineModified();
|
||||||
|
gui_chat_console->onPromptModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that the size is still correct
|
// Make sure that the size is still correct
|
||||||
|
@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "client/fontengine.h"
|
#include "client/fontengine.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "gettext.h"
|
#include "gettext.h"
|
||||||
|
#include <algorithm>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "touchscreengui.h"
|
#include "touchscreengui.h"
|
||||||
|
|
||||||
@ -132,6 +133,7 @@ void GUIChatConsole::openConsole(f32 scale)
|
|||||||
|
|
||||||
m_desired_height = scale * m_screensize.Y;
|
m_desired_height = scale * m_screensize.Y;
|
||||||
reformatConsole();
|
reformatConsole();
|
||||||
|
updateVScrollBar(false, true);
|
||||||
m_animate_time_old = porting::getTimeMs();
|
m_animate_time_old = porting::getTimeMs();
|
||||||
IGUIElement::setVisible(true);
|
IGUIElement::setVisible(true);
|
||||||
m_vscrollbar->setVisible(true);
|
m_vscrollbar->setVisible(true);
|
||||||
@ -228,6 +230,7 @@ void GUIChatConsole::draw()
|
|||||||
m_screensize = screensize;
|
m_screensize = screensize;
|
||||||
m_desired_height = m_desired_height_fraction * m_screensize.Y;
|
m_desired_height = m_desired_height_fraction * m_screensize.Y;
|
||||||
reformatConsole();
|
reformatConsole();
|
||||||
|
updateVScrollBar(true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Animation
|
// Animation
|
||||||
@ -255,7 +258,12 @@ void GUIChatConsole::reformatConsole()
|
|||||||
recalculateConsolePosition();
|
recalculateConsolePosition();
|
||||||
m_chat_backend->reformat(cols, rows);
|
m_chat_backend->reformat(cols, rows);
|
||||||
|
|
||||||
updateVScrollBar();
|
m_mark_begin.reset();
|
||||||
|
m_mark_end.reset();
|
||||||
|
m_cursor_press_pos.reset();
|
||||||
|
m_history_marking = false;
|
||||||
|
m_prompt_marking = false;
|
||||||
|
m_long_press = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIChatConsole::recalculateConsolePosition()
|
void GUIChatConsole::recalculateConsolePosition()
|
||||||
@ -367,6 +375,8 @@ void GUIChatConsole::drawText()
|
|||||||
ChatSelection real_mark_begin = m_mark_end > m_mark_begin ? m_mark_begin : m_mark_end;
|
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;
|
ChatSelection real_mark_end = m_mark_end > m_mark_begin ? m_mark_end : m_mark_begin;
|
||||||
if (real_mark_begin != real_mark_end &&
|
if (real_mark_begin != real_mark_end &&
|
||||||
|
real_mark_begin.selection_type == ChatSelection::SELECTION_HISTORY &&
|
||||||
|
real_mark_end.selection_type == ChatSelection::SELECTION_HISTORY &&
|
||||||
(s32)row + scroll_pos >= real_mark_begin.row + real_mark_begin.scroll &&
|
(s32)row + scroll_pos >= real_mark_begin.row + real_mark_begin.scroll &&
|
||||||
(s32)row + scroll_pos <= real_mark_end.row + real_mark_end.scroll) {
|
(s32)row + scroll_pos <= real_mark_end.row + real_mark_end.scroll) {
|
||||||
ChatFormattedFragment fragment_first = line.fragments[0];
|
ChatFormattedFragment fragment_first = line.fragments[0];
|
||||||
@ -454,23 +464,61 @@ void GUIChatConsole::drawPrompt()
|
|||||||
|
|
||||||
ChatPrompt& prompt = m_chat_backend->getPrompt();
|
ChatPrompt& prompt = m_chat_backend->getPrompt();
|
||||||
std::wstring prompt_text = prompt.getVisiblePortion();
|
std::wstring prompt_text = prompt.getVisiblePortion();
|
||||||
|
std::replace_if(prompt_text.begin(), prompt_text.end(),
|
||||||
|
[](wchar_t c) { return (c == L'\n' || c == L'\r'); }, L' ');
|
||||||
|
|
||||||
|
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 &&
|
||||||
|
real_mark_begin.selection_type == ChatSelection::SELECTION_PROMPT &&
|
||||||
|
real_mark_end.selection_type == ChatSelection::SELECTION_PROMPT) {
|
||||||
|
std::wstring begin_text = L"]";
|
||||||
|
int begin_text_size = m_font->getDimension(begin_text.c_str()).Width;
|
||||||
|
int text_pos = m_fontsize.X + begin_text_size;
|
||||||
|
|
||||||
|
s32 x_begin = text_pos;
|
||||||
|
s32 text_size = m_font->getDimension(prompt_text.c_str()).Width;
|
||||||
|
s32 x_end = x_begin + text_size;
|
||||||
|
|
||||||
|
int current_scroll = prompt.getViewPosition();
|
||||||
|
if (real_mark_begin.character > 0) {
|
||||||
|
irr::core::stringw text = prompt_text.c_str();
|
||||||
|
int scroll_offset = real_mark_begin.scroll - current_scroll;
|
||||||
|
int length = scroll_offset + real_mark_begin.character;
|
||||||
|
length = MYMIN(MYMAX(length, 0), prompt_text.size() - 1);
|
||||||
|
text = text.subString(1, length);
|
||||||
|
s32 text_size = m_font->getDimension(text.c_str()).Width;
|
||||||
|
x_begin = text_pos + text_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (real_mark_end.character < prompt_text.size() - 1) {
|
||||||
|
irr::core::stringw text = prompt_text.c_str();
|
||||||
|
int scroll_offset = real_mark_end.scroll - current_scroll;
|
||||||
|
int length = scroll_offset + real_mark_end.character;
|
||||||
|
if (real_mark_end.x_max)
|
||||||
|
length++;
|
||||||
|
length = MYMIN(MYMAX(length, 0), prompt_text.size() - 1);
|
||||||
|
text = text.subString(1, length);
|
||||||
|
s32 text_size = m_font->getDimension(text.c_str()).Width;
|
||||||
|
x_end = text_pos + 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);
|
||||||
|
}
|
||||||
|
|
||||||
// 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(
|
core::rect<s32> destrect(
|
||||||
x, y, x + m_fontsize.X, y + m_fontsize.Y);
|
m_fontsize.X, y, prompt_text.size() * m_fontsize.X, y + m_fontsize.Y);
|
||||||
m_font->draw(
|
m_font->draw(
|
||||||
ws,
|
prompt_text.c_str(),
|
||||||
destrect,
|
destrect,
|
||||||
video::SColor(255, 255, 255, 255),
|
video::SColor(255, 255, 255, 255),
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
&AbsoluteClippingRect);
|
&AbsoluteClippingRect);
|
||||||
}
|
|
||||||
|
|
||||||
// Draw the cursor during on periods
|
// Draw the cursor during on periods
|
||||||
if ((m_cursor_blink & 0x8000) != 0)
|
if ((m_cursor_blink & 0x8000) != 0)
|
||||||
@ -480,7 +528,9 @@ void GUIChatConsole::drawPrompt()
|
|||||||
{
|
{
|
||||||
s32 cursor_len = prompt.getCursorLength();
|
s32 cursor_len = prompt.getCursorLength();
|
||||||
video::IVideoDriver* driver = Environment->getVideoDriver();
|
video::IVideoDriver* driver = Environment->getVideoDriver();
|
||||||
s32 x = (1 + cursor_pos) * m_fontsize.X;
|
std::wstring text = prompt_text.substr(0, cursor_pos);
|
||||||
|
s32 x = m_font->getDimension(text.c_str()).Width + m_fontsize.X;
|
||||||
|
|
||||||
core::rect<s32> destrect(
|
core::rect<s32> destrect(
|
||||||
x,
|
x,
|
||||||
y + m_fontsize.Y * (1.0 - m_cursor_height),
|
y + m_fontsize.Y * (1.0 - m_cursor_height),
|
||||||
@ -494,7 +544,6 @@ void GUIChatConsole::drawPrompt()
|
|||||||
&AbsoluteClippingRect);
|
&AbsoluteClippingRect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -507,7 +556,7 @@ ChatSelection GUIChatConsole::getCursorPos(s32 x, s32 y)
|
|||||||
|
|
||||||
ChatBuffer& buf = m_chat_backend->getConsoleBuffer();
|
ChatBuffer& buf = m_chat_backend->getConsoleBuffer();
|
||||||
selection.scroll = buf.getScrollPos();
|
selection.scroll = buf.getScrollPos();
|
||||||
selection.initialized = true;
|
selection.selection_type = ChatSelection::SELECTION_HISTORY;
|
||||||
|
|
||||||
s32 line_height = m_fontsize.Y;
|
s32 line_height = m_fontsize.Y;
|
||||||
s32 y_min = m_height - m_desired_height;
|
s32 y_min = m_height - m_desired_height;
|
||||||
@ -533,7 +582,7 @@ ChatSelection GUIChatConsole::getCursorPos(s32 x, s32 y)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ChatFormattedLine line = buf.getFormattedLine(selection.row);
|
ChatFormattedLine line = buf.getFormattedLine(selection.row);
|
||||||
selection.row_buf = line.line_index;
|
selection.line_index = line.line_index;
|
||||||
int current_row = selection.row;
|
int current_row = selection.row;
|
||||||
|
|
||||||
while (!line.first) {
|
while (!line.first) {
|
||||||
@ -585,6 +634,58 @@ ChatSelection GUIChatConsole::getCursorPos(s32 x, s32 y)
|
|||||||
return selection;
|
return selection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChatSelection GUIChatConsole::getPromptCursorPos(s32 x, s32 y)
|
||||||
|
{
|
||||||
|
ChatSelection selection;
|
||||||
|
|
||||||
|
if (m_font == NULL)
|
||||||
|
return selection;
|
||||||
|
|
||||||
|
ChatPrompt& prompt = m_chat_backend->getPrompt();
|
||||||
|
|
||||||
|
selection.selection_type = ChatSelection::SELECTION_PROMPT;
|
||||||
|
selection.scroll = prompt.getViewPosition();
|
||||||
|
|
||||||
|
std::wstring prompt_text = prompt.getVisiblePortion();
|
||||||
|
irr::core::stringw text = prompt_text.c_str();
|
||||||
|
text = text.subString(1, prompt_text.size() - 1);
|
||||||
|
|
||||||
|
std::wstring begin_text = L"]";
|
||||||
|
int begin_text_size = m_font->getDimension(begin_text.c_str()).Width;
|
||||||
|
int text_pos = m_fontsize.X + begin_text_size;
|
||||||
|
int pos = m_font->getCharacterFromPos(text.c_str(), x - text_pos);
|
||||||
|
|
||||||
|
if (pos == -1) {
|
||||||
|
selection.x_max = true;
|
||||||
|
selection.character = text.size() - 1;
|
||||||
|
} else {
|
||||||
|
selection.character = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return selection;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatSelection GUIChatConsole::getCurrentPromptCursorPos()
|
||||||
|
{
|
||||||
|
ChatSelection selection;
|
||||||
|
|
||||||
|
if (m_font == NULL)
|
||||||
|
return selection;
|
||||||
|
|
||||||
|
ChatPrompt& prompt = m_chat_backend->getPrompt();
|
||||||
|
|
||||||
|
selection.selection_type = ChatSelection::SELECTION_PROMPT;
|
||||||
|
selection.scroll = prompt.getViewPosition();
|
||||||
|
selection.character = prompt.getVisibleCursorPosition() - 1;
|
||||||
|
|
||||||
|
if ((unsigned int)selection.character > prompt.getLine().size() - selection.scroll - 1) {
|
||||||
|
selection.character--;
|
||||||
|
selection.x_max = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return selection;
|
||||||
|
}
|
||||||
|
|
||||||
irr::core::stringc GUIChatConsole::getSelectedText()
|
irr::core::stringc GUIChatConsole::getSelectedText()
|
||||||
{
|
{
|
||||||
if (m_font == NULL)
|
if (m_font == NULL)
|
||||||
@ -601,11 +702,19 @@ irr::core::stringc GUIChatConsole::getSelectedText()
|
|||||||
|
|
||||||
ChatBuffer& buf = m_chat_backend->getConsoleBuffer();
|
ChatBuffer& buf = m_chat_backend->getConsoleBuffer();
|
||||||
|
|
||||||
for (int row = real_mark_begin.row_buf; row < real_mark_end.row_buf + 1; row++) {
|
const ChatLine& first_line = buf.getLine(0);
|
||||||
|
int first_line_index = first_line.line_index;
|
||||||
|
int mark_begin_row_buf = real_mark_begin.line_index - first_line_index;
|
||||||
|
int mark_end_row_buf = real_mark_end.line_index - first_line_index;
|
||||||
|
|
||||||
|
if (mark_begin_row_buf < 0 || mark_end_row_buf < 0)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
for (int row = mark_begin_row_buf; row < mark_end_row_buf + 1; row++) {
|
||||||
const ChatLine& line = buf.getLine(row);
|
const ChatLine& line = buf.getLine(row);
|
||||||
|
|
||||||
std::vector<ChatFormattedLine> formatted_lines;
|
std::vector<ChatFormattedLine> formatted_lines;
|
||||||
buf.formatChatLine(line, 0, buf.getColsCount(), formatted_lines);
|
buf.formatChatLine(line, buf.getColsCount(), formatted_lines);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < formatted_lines.size(); i++) {
|
for (unsigned int i = 0; i < formatted_lines.size(); i++) {
|
||||||
const ChatFormattedLine &line = formatted_lines[i];
|
const ChatFormattedLine &line = formatted_lines[i];
|
||||||
@ -615,7 +724,7 @@ irr::core::stringc GUIChatConsole::getSelectedText()
|
|||||||
|
|
||||||
for (unsigned int k = 0; k < fragment.text.size(); k++) {
|
for (unsigned int k = 0; k < fragment.text.size(); k++) {
|
||||||
if (!add_to_string &&
|
if (!add_to_string &&
|
||||||
row == real_mark_begin.row_buf &&
|
row == mark_begin_row_buf &&
|
||||||
i == real_mark_begin.line &&
|
i == real_mark_begin.line &&
|
||||||
j == real_mark_begin.fragment &&
|
j == real_mark_begin.fragment &&
|
||||||
k == real_mark_begin.character) {
|
k == real_mark_begin.character) {
|
||||||
@ -626,7 +735,7 @@ irr::core::stringc GUIChatConsole::getSelectedText()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (add_to_string) {
|
if (add_to_string) {
|
||||||
if (row == real_mark_end.row_buf &&
|
if (row == mark_end_row_buf &&
|
||||||
i == real_mark_end.line &&
|
i == real_mark_end.line &&
|
||||||
j == real_mark_end.fragment &&
|
j == real_mark_end.fragment &&
|
||||||
k == real_mark_end.character) {
|
k == real_mark_end.character) {
|
||||||
@ -643,7 +752,7 @@ irr::core::stringc GUIChatConsole::getSelectedText()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (row < real_mark_end.row_buf) {
|
if (row < mark_end_row_buf) {
|
||||||
text += L"\n";
|
text += L"\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -654,6 +763,80 @@ irr::core::stringc GUIChatConsole::getSelectedText()
|
|||||||
return text_c;
|
return text_c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
irr::core::stringc GUIChatConsole::getPromptSelectedText()
|
||||||
|
{
|
||||||
|
if (m_font == NULL)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
if (m_mark_begin == m_mark_end)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
ChatPrompt& prompt = m_chat_backend->getPrompt();
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
std::wstring prompt_text = prompt.getLine();
|
||||||
|
|
||||||
|
if (real_mark_end.scroll + real_mark_end.character > prompt_text.size())
|
||||||
|
return "";
|
||||||
|
|
||||||
|
irr::core::stringw text = prompt_text.c_str();
|
||||||
|
int begin = real_mark_begin.scroll + real_mark_begin.character;
|
||||||
|
int length = real_mark_end.scroll + real_mark_end.character - begin;
|
||||||
|
if (real_mark_end.x_max)
|
||||||
|
length++;
|
||||||
|
text = text.subString(begin, length);
|
||||||
|
|
||||||
|
irr::core::stringc text_c;
|
||||||
|
text_c = wide_to_utf8(text.c_str()).c_str();
|
||||||
|
return text_c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GUIChatConsole::movePromptCursor(s32 x, s32 y)
|
||||||
|
{
|
||||||
|
ChatSelection selection = getPromptCursorPos(x, y);
|
||||||
|
|
||||||
|
int cursor_pos = selection.scroll + selection.character;
|
||||||
|
if (selection.x_max)
|
||||||
|
cursor_pos++;
|
||||||
|
|
||||||
|
ChatPrompt& prompt = m_chat_backend->getPrompt();
|
||||||
|
prompt.setCursorPos(cursor_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GUIChatConsole::deletePromptSelection()
|
||||||
|
{
|
||||||
|
if (m_mark_begin.selection_type != ChatSelection::SELECTION_PROMPT ||
|
||||||
|
m_mark_end.selection_type != ChatSelection::SELECTION_PROMPT ||
|
||||||
|
m_mark_begin == m_mark_end)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ChatPrompt& prompt = m_chat_backend->getPrompt();
|
||||||
|
int scroll_pos = prompt.getViewPosition();
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
int pos_begin = real_mark_begin.scroll + real_mark_begin.character;
|
||||||
|
int pos_end = real_mark_end.scroll + real_mark_end.character;
|
||||||
|
if (real_mark_end.x_max)
|
||||||
|
pos_end++;
|
||||||
|
|
||||||
|
std::wstring prompt_text = prompt.getLine();
|
||||||
|
std::wstring new_text;
|
||||||
|
new_text = prompt_text.substr(0, pos_begin);
|
||||||
|
new_text += prompt_text.substr(pos_end, prompt_text.size() - pos_end);
|
||||||
|
|
||||||
|
prompt.replace(new_text);
|
||||||
|
|
||||||
|
int cursor_pos = real_mark_begin.scroll + real_mark_begin.character;
|
||||||
|
prompt.setCursorPos(cursor_pos);
|
||||||
|
prompt.setViewPosition(scroll_pos);
|
||||||
|
|
||||||
|
m_mark_begin.reset();
|
||||||
|
m_mark_end.reset();
|
||||||
|
}
|
||||||
|
|
||||||
bool GUIChatConsole::OnEvent(const SEvent& event)
|
bool GUIChatConsole::OnEvent(const SEvent& event)
|
||||||
{
|
{
|
||||||
@ -702,6 +885,8 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||||||
if (m_close_on_enter) {
|
if (m_close_on_enter) {
|
||||||
closeConsole();
|
closeConsole();
|
||||||
m_close_on_enter = false;
|
m_close_on_enter = false;
|
||||||
|
} else {
|
||||||
|
updateVScrollBar(true, true);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -721,11 +906,11 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||||||
}
|
}
|
||||||
else if(event.KeyInput.Key == KEY_LEFT || event.KeyInput.Key == KEY_RIGHT)
|
else if(event.KeyInput.Key == KEY_LEFT || event.KeyInput.Key == KEY_RIGHT)
|
||||||
{
|
{
|
||||||
|
ChatSelection old_pos = getCurrentPromptCursorPos();
|
||||||
|
|
||||||
// Left/right pressed
|
// Left/right pressed
|
||||||
// Move/select character/word to the left depending on control and shift keys
|
// Move/select character/word to the left depending on control and shift keys
|
||||||
ChatPrompt::CursorOp op = event.KeyInput.Shift ?
|
ChatPrompt::CursorOp op = ChatPrompt::CURSOROP_MOVE;
|
||||||
ChatPrompt::CURSOROP_SELECT :
|
|
||||||
ChatPrompt::CURSOROP_MOVE;
|
|
||||||
ChatPrompt::CursorOpDir dir = event.KeyInput.Key == KEY_LEFT ?
|
ChatPrompt::CursorOpDir dir = event.KeyInput.Key == KEY_LEFT ?
|
||||||
ChatPrompt::CURSOROP_DIR_LEFT :
|
ChatPrompt::CURSOROP_DIR_LEFT :
|
||||||
ChatPrompt::CURSOROP_DIR_RIGHT;
|
ChatPrompt::CURSOROP_DIR_RIGHT;
|
||||||
@ -733,30 +918,86 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||||||
ChatPrompt::CURSOROP_SCOPE_WORD :
|
ChatPrompt::CURSOROP_SCOPE_WORD :
|
||||||
ChatPrompt::CURSOROP_SCOPE_CHARACTER;
|
ChatPrompt::CURSOROP_SCOPE_CHARACTER;
|
||||||
prompt.cursorOperation(op, dir, scope);
|
prompt.cursorOperation(op, dir, scope);
|
||||||
|
|
||||||
|
if (event.KeyInput.Shift) {
|
||||||
|
if (m_mark_begin.selection_type != ChatSelection::SELECTION_PROMPT ||
|
||||||
|
m_mark_end.selection_type != ChatSelection::SELECTION_PROMPT) {
|
||||||
|
m_mark_begin = old_pos;
|
||||||
|
}
|
||||||
|
m_mark_end = getCurrentPromptCursorPos();
|
||||||
|
} else {
|
||||||
|
if (m_mark_begin.selection_type == ChatSelection::SELECTION_PROMPT &&
|
||||||
|
m_mark_end.selection_type == ChatSelection::SELECTION_PROMPT) {
|
||||||
|
m_mark_begin.reset();
|
||||||
|
m_mark_end.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if(event.KeyInput.Key == KEY_HOME)
|
else if(event.KeyInput.Key == KEY_HOME)
|
||||||
{
|
{
|
||||||
|
ChatSelection old_pos = getCurrentPromptCursorPos();
|
||||||
|
|
||||||
// Home pressed
|
// Home pressed
|
||||||
// move to beginning of line
|
// move to beginning of line
|
||||||
prompt.cursorOperation(
|
prompt.cursorOperation(
|
||||||
ChatPrompt::CURSOROP_MOVE,
|
ChatPrompt::CURSOROP_MOVE,
|
||||||
ChatPrompt::CURSOROP_DIR_LEFT,
|
ChatPrompt::CURSOROP_DIR_LEFT,
|
||||||
ChatPrompt::CURSOROP_SCOPE_LINE);
|
ChatPrompt::CURSOROP_SCOPE_LINE);
|
||||||
|
|
||||||
|
if (event.KeyInput.Shift) {
|
||||||
|
if (m_mark_begin.selection_type != ChatSelection::SELECTION_PROMPT ||
|
||||||
|
m_mark_end.selection_type != ChatSelection::SELECTION_PROMPT) {
|
||||||
|
m_mark_begin = old_pos;
|
||||||
|
}
|
||||||
|
m_mark_end = getCurrentPromptCursorPos();
|
||||||
|
} else {
|
||||||
|
if (m_mark_begin.selection_type == ChatSelection::SELECTION_PROMPT &&
|
||||||
|
m_mark_end.selection_type == ChatSelection::SELECTION_PROMPT) {
|
||||||
|
m_mark_begin.reset();
|
||||||
|
m_mark_end.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if(event.KeyInput.Key == KEY_END)
|
else if(event.KeyInput.Key == KEY_END)
|
||||||
{
|
{
|
||||||
|
ChatSelection old_pos = getCurrentPromptCursorPos();
|
||||||
|
|
||||||
// End pressed
|
// End pressed
|
||||||
// move to end of line
|
// move to end of line
|
||||||
prompt.cursorOperation(
|
prompt.cursorOperation(
|
||||||
ChatPrompt::CURSOROP_MOVE,
|
ChatPrompt::CURSOROP_MOVE,
|
||||||
ChatPrompt::CURSOROP_DIR_RIGHT,
|
ChatPrompt::CURSOROP_DIR_RIGHT,
|
||||||
ChatPrompt::CURSOROP_SCOPE_LINE);
|
ChatPrompt::CURSOROP_SCOPE_LINE);
|
||||||
|
|
||||||
|
if (event.KeyInput.Shift) {
|
||||||
|
if (m_mark_begin.selection_type != ChatSelection::SELECTION_PROMPT ||
|
||||||
|
m_mark_end.selection_type != ChatSelection::SELECTION_PROMPT) {
|
||||||
|
m_mark_begin = old_pos;
|
||||||
|
}
|
||||||
|
m_mark_end = getCurrentPromptCursorPos();
|
||||||
|
} else {
|
||||||
|
if (m_mark_begin.selection_type == ChatSelection::SELECTION_PROMPT &&
|
||||||
|
m_mark_end.selection_type == ChatSelection::SELECTION_PROMPT) {
|
||||||
|
m_mark_begin.reset();
|
||||||
|
m_mark_end.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if(event.KeyInput.Key == KEY_BACK)
|
else if(event.KeyInput.Key == KEY_BACK)
|
||||||
{
|
{
|
||||||
|
if (m_mark_begin.selection_type == ChatSelection::SELECTION_PROMPT &&
|
||||||
|
m_mark_end.selection_type == ChatSelection::SELECTION_PROMPT &&
|
||||||
|
m_mark_begin != m_mark_end) {
|
||||||
|
deletePromptSelection();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Backspace or Ctrl-Backspace pressed
|
// Backspace or Ctrl-Backspace pressed
|
||||||
// delete character / word to the left
|
// delete character / word to the left
|
||||||
ChatPrompt::CursorOpScope scope =
|
ChatPrompt::CursorOpScope scope =
|
||||||
@ -771,6 +1012,13 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||||||
}
|
}
|
||||||
else if(event.KeyInput.Key == KEY_DELETE)
|
else if(event.KeyInput.Key == KEY_DELETE)
|
||||||
{
|
{
|
||||||
|
if (m_mark_begin.selection_type == ChatSelection::SELECTION_PROMPT &&
|
||||||
|
m_mark_end.selection_type == ChatSelection::SELECTION_PROMPT &&
|
||||||
|
m_mark_begin != m_mark_end) {
|
||||||
|
deletePromptSelection();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Delete or Ctrl-Delete pressed
|
// Delete or Ctrl-Delete pressed
|
||||||
// delete character / word to the right
|
// delete character / word to the right
|
||||||
ChatPrompt::CursorOpScope scope =
|
ChatPrompt::CursorOpScope scope =
|
||||||
@ -785,21 +1033,43 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||||||
}
|
}
|
||||||
else if(event.KeyInput.Key == KEY_KEY_A && event.KeyInput.Control)
|
else if(event.KeyInput.Key == KEY_KEY_A && event.KeyInput.Control)
|
||||||
{
|
{
|
||||||
// Ctrl-A pressed
|
if (prompt.getLine().size() > 0) {
|
||||||
// Select all text
|
ChatPrompt& prompt = m_chat_backend->getPrompt();
|
||||||
|
|
||||||
|
m_mark_begin.reset();
|
||||||
|
m_mark_begin.selection_type = ChatSelection::SELECTION_PROMPT;
|
||||||
|
m_mark_begin.scroll = 0;
|
||||||
|
m_mark_begin.character = 0;
|
||||||
|
|
||||||
|
m_mark_end.reset();
|
||||||
|
m_mark_end.selection_type = ChatSelection::SELECTION_PROMPT;
|
||||||
|
m_mark_end.scroll = 0;
|
||||||
|
m_mark_end.character = prompt.getLine().size() - 1;
|
||||||
|
m_mark_end.x_max = true;
|
||||||
|
|
||||||
prompt.cursorOperation(
|
prompt.cursorOperation(
|
||||||
ChatPrompt::CURSOROP_SELECT,
|
ChatPrompt::CURSOROP_MOVE,
|
||||||
ChatPrompt::CURSOROP_DIR_LEFT, // Ignored
|
ChatPrompt::CURSOROP_DIR_RIGHT,
|
||||||
ChatPrompt::CURSOROP_SCOPE_LINE);
|
ChatPrompt::CURSOROP_SCOPE_LINE);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
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) {
|
if (m_mark_begin != m_mark_end) {
|
||||||
|
if (m_mark_begin.selection_type == ChatSelection::SELECTION_PROMPT &&
|
||||||
|
m_mark_end.selection_type == ChatSelection::SELECTION_PROMPT) {
|
||||||
|
irr::core::stringc text = getPromptSelectedText();
|
||||||
|
Environment->getOSOperator()->copyToClipboard(text.c_str());
|
||||||
|
return true;
|
||||||
|
} else if (m_mark_begin.selection_type == ChatSelection::SELECTION_HISTORY &&
|
||||||
|
m_mark_end.selection_type == ChatSelection::SELECTION_HISTORY) {
|
||||||
irr::core::stringc text = getSelectedText();
|
irr::core::stringc text = getSelectedText();
|
||||||
Environment->getOSOperator()->copyToClipboard(text.c_str());
|
Environment->getOSOperator()->copyToClipboard(text.c_str());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Ctrl-C pressed
|
// Ctrl-C pressed
|
||||||
// Copy text to clipboard
|
// Copy text to clipboard
|
||||||
@ -812,6 +1082,12 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||||||
}
|
}
|
||||||
else if(event.KeyInput.Key == KEY_KEY_V && event.KeyInput.Control)
|
else if(event.KeyInput.Key == KEY_KEY_V && event.KeyInput.Control)
|
||||||
{
|
{
|
||||||
|
if (m_mark_begin.selection_type == ChatSelection::SELECTION_PROMPT &&
|
||||||
|
m_mark_end.selection_type == ChatSelection::SELECTION_PROMPT &&
|
||||||
|
m_mark_begin != m_mark_end) {
|
||||||
|
deletePromptSelection();
|
||||||
|
}
|
||||||
|
|
||||||
// Ctrl-V pressed
|
// Ctrl-V pressed
|
||||||
// paste text from clipboard
|
// paste text from clipboard
|
||||||
if (prompt.getCursorLength() > 0) {
|
if (prompt.getCursorLength() > 0) {
|
||||||
@ -830,6 +1106,15 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||||||
}
|
}
|
||||||
else if(event.KeyInput.Key == KEY_KEY_X && event.KeyInput.Control)
|
else if(event.KeyInput.Key == KEY_KEY_X && event.KeyInput.Control)
|
||||||
{
|
{
|
||||||
|
if (m_mark_begin.selection_type == ChatSelection::SELECTION_PROMPT &&
|
||||||
|
m_mark_end.selection_type == ChatSelection::SELECTION_PROMPT &&
|
||||||
|
m_mark_begin != m_mark_end) {
|
||||||
|
irr::core::stringc text = getPromptSelectedText();
|
||||||
|
Environment->getOSOperator()->copyToClipboard(text.c_str());
|
||||||
|
deletePromptSelection();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Ctrl-X pressed
|
// Ctrl-X pressed
|
||||||
// Cut text to clipboard
|
// Cut text to clipboard
|
||||||
if (prompt.getCursorLength() <= 0)
|
if (prompt.getCursorLength() <= 0)
|
||||||
@ -872,6 +1157,12 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||||||
prompt.nickCompletion(names, backwards);
|
prompt.nickCompletion(names, backwards);
|
||||||
return true;
|
return true;
|
||||||
} else if (!iswcntrl(event.KeyInput.Char) && !event.KeyInput.Control) {
|
} else if (!iswcntrl(event.KeyInput.Char) && !event.KeyInput.Control) {
|
||||||
|
if (m_mark_begin.selection_type == ChatSelection::SELECTION_PROMPT &&
|
||||||
|
m_mark_end.selection_type == ChatSelection::SELECTION_PROMPT &&
|
||||||
|
m_mark_begin != m_mark_end) {
|
||||||
|
deletePromptSelection();
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(__linux__) && (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 9)
|
#if defined(__linux__) && (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 9)
|
||||||
wchar_t wc = L'_';
|
wchar_t wc = L'_';
|
||||||
mbtowc( &wc, (char *) &event.KeyInput.Char, sizeof(event.KeyInput.Char) );
|
mbtowc( &wc, (char *) &event.KeyInput.Char, sizeof(event.KeyInput.Char) );
|
||||||
@ -887,6 +1178,12 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||||||
{
|
{
|
||||||
if (event.SDLTextEvent.Type == ESDLET_TEXTINPUT)
|
if (event.SDLTextEvent.Type == ESDLET_TEXTINPUT)
|
||||||
{
|
{
|
||||||
|
if (m_mark_begin.selection_type == ChatSelection::SELECTION_PROMPT &&
|
||||||
|
m_mark_end.selection_type == ChatSelection::SELECTION_PROMPT &&
|
||||||
|
m_mark_begin != m_mark_end) {
|
||||||
|
deletePromptSelection();
|
||||||
|
}
|
||||||
|
|
||||||
std::wstring text = utf8_to_wide(event.SDLTextEvent.Text);
|
std::wstring text = utf8_to_wide(event.SDLTextEvent.Text);
|
||||||
|
|
||||||
for (u32 i = 0; i < text.size(); i++)
|
for (u32 i = 0; i < text.size(); i++)
|
||||||
@ -905,13 +1202,41 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||||||
m_chat_backend->scroll(rows);
|
m_chat_backend->scroll(rows);
|
||||||
m_vscrollbar->setPos(m_vscrollbar->getPos() + rows);
|
m_vscrollbar->setPos(m_vscrollbar->getPos() + rows);
|
||||||
} else if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) {
|
} else if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) {
|
||||||
m_mouse_marking = true;
|
u32 row = m_chat_backend->getConsoleBuffer().getRows();
|
||||||
|
s32 prompt_y = row * m_fontsize.Y + m_height - m_desired_height;
|
||||||
|
|
||||||
|
if (event.MouseInput.Y >= prompt_y) {
|
||||||
|
m_prompt_marking = true;
|
||||||
|
if (event.MouseInput.Shift) {
|
||||||
|
if (m_mark_begin.selection_type != ChatSelection::SELECTION_PROMPT ||
|
||||||
|
m_mark_end.selection_type != ChatSelection::SELECTION_PROMPT) {
|
||||||
|
m_mark_begin = getCurrentPromptCursorPos();
|
||||||
|
m_mark_end = getPromptCursorPos(event.MouseInput.X, event.MouseInput.Y);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_mark_begin = getPromptCursorPos(event.MouseInput.X, event.MouseInput.Y);
|
||||||
|
m_mark_end = m_mark_begin;
|
||||||
|
}
|
||||||
|
movePromptCursor(event.MouseInput.X, event.MouseInput.Y);
|
||||||
|
} else {
|
||||||
|
m_history_marking = true;
|
||||||
m_mark_begin = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
|
m_mark_begin = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
|
||||||
m_mark_end = m_mark_begin;
|
m_mark_end = m_mark_begin;
|
||||||
|
}
|
||||||
} else if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP) {
|
} else if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP) {
|
||||||
if (m_mouse_marking) {
|
if (m_prompt_marking) {
|
||||||
|
m_mark_end = getPromptCursorPos(event.MouseInput.X, event.MouseInput.Y);
|
||||||
|
m_prompt_marking = false;
|
||||||
|
|
||||||
|
if (!event.MouseInput.Shift) {
|
||||||
|
if (m_mark_begin == m_mark_end) {
|
||||||
|
m_mark_begin.reset();
|
||||||
|
m_mark_end.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (m_history_marking) {
|
||||||
m_mark_end = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
|
m_mark_end = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
|
||||||
m_mouse_marking = false;
|
m_history_marking = false;
|
||||||
|
|
||||||
if (m_mark_begin == m_mark_end) {
|
if (m_mark_begin == m_mark_end) {
|
||||||
m_mark_begin.reset();
|
m_mark_begin.reset();
|
||||||
@ -919,7 +1244,10 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (event.MouseInput.Event == EMIE_MOUSE_MOVED) {
|
} else if (event.MouseInput.Event == EMIE_MOUSE_MOVED) {
|
||||||
if (m_mouse_marking) {
|
if (m_prompt_marking) {
|
||||||
|
m_mark_end = getPromptCursorPos(event.MouseInput.X, event.MouseInput.Y);
|
||||||
|
movePromptCursor(event.MouseInput.X, event.MouseInput.Y);
|
||||||
|
} else if (m_history_marking) {
|
||||||
m_mark_end = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
|
m_mark_end = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -929,19 +1257,52 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||||||
#ifdef HAVE_TOUCHSCREENGUI
|
#ifdef HAVE_TOUCHSCREENGUI
|
||||||
else if (event.EventType == EET_TOUCH_INPUT_EVENT) {
|
else if (event.EventType == EET_TOUCH_INPUT_EVENT) {
|
||||||
if (event.TouchInput.Event == irr::ETIE_PRESSED_DOWN) {
|
if (event.TouchInput.Event == irr::ETIE_PRESSED_DOWN) {
|
||||||
m_mouse_marking = false;
|
m_history_marking = false;
|
||||||
|
m_prompt_marking = false;
|
||||||
m_long_press = false;
|
m_long_press = false;
|
||||||
m_cursor_press_pos = getCursorPos(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;
|
||||||
|
|
||||||
ChatSelection real_mark_begin = m_mark_end > m_mark_begin ? m_mark_begin : m_mark_end;
|
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;
|
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) {
|
if (event.TouchInput.Y >= prompt_y) {
|
||||||
|
|
||||||
|
m_cursor_press_pos = getPromptCursorPos(event.TouchInput.X, event.TouchInput.Y);
|
||||||
|
|
||||||
|
if (real_mark_begin.selection_type != ChatSelection::SELECTION_PROMPT ||
|
||||||
|
real_mark_end.selection_type != ChatSelection::SELECTION_PROMPT ||
|
||||||
|
m_cursor_press_pos < real_mark_begin ||
|
||||||
|
m_cursor_press_pos > real_mark_end) {
|
||||||
m_mark_begin = m_cursor_press_pos;
|
m_mark_begin = m_cursor_press_pos;
|
||||||
m_mark_end = m_cursor_press_pos;
|
m_mark_end = m_cursor_press_pos;
|
||||||
m_mouse_marking = true;
|
m_prompt_marking = true;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
m_cursor_press_pos = getCursorPos(event.TouchInput.X, event.TouchInput.Y);
|
||||||
|
|
||||||
|
if (real_mark_begin.selection_type != ChatSelection::SELECTION_HISTORY ||
|
||||||
|
real_mark_end.selection_type != ChatSelection::SELECTION_HISTORY ||
|
||||||
|
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_history_marking = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else if (event.TouchInput.Event == irr::ETIE_LEFT_UP) {
|
} else if (event.TouchInput.Event == irr::ETIE_LEFT_UP) {
|
||||||
|
if (m_prompt_marking) {
|
||||||
|
ChatSelection cursor_pos = getPromptCursorPos(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_prompt_marking = false;
|
||||||
|
} else if (m_history_marking) {
|
||||||
ChatSelection cursor_pos = getCursorPos(event.TouchInput.X, event.TouchInput.Y);
|
ChatSelection cursor_pos = getCursorPos(event.TouchInput.X, event.TouchInput.Y);
|
||||||
|
|
||||||
if (!m_long_press && m_cursor_press_pos == cursor_pos) {
|
if (!m_long_press && m_cursor_press_pos == cursor_pos) {
|
||||||
@ -949,27 +1310,48 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||||||
m_mark_end.reset();
|
m_mark_end.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_history_marking = false;
|
||||||
|
}
|
||||||
|
|
||||||
m_cursor_press_pos.reset();
|
m_cursor_press_pos.reset();
|
||||||
m_mouse_marking = false;
|
|
||||||
m_long_press = false;
|
m_long_press = false;
|
||||||
|
|
||||||
} else if (event.TouchInput.Event == irr::ETIE_MOVED) {
|
} else if (event.TouchInput.Event == irr::ETIE_MOVED) {
|
||||||
ChatSelection cursor_pos = getCursorPos(event.TouchInput.X, event.TouchInput.Y);
|
ChatSelection cursor_pos = getCursorPos(event.TouchInput.X, event.TouchInput.Y);
|
||||||
|
ChatSelection prompt_cursor_pos = getPromptCursorPos(event.TouchInput.X, event.TouchInput.Y);
|
||||||
|
|
||||||
if (!m_mouse_marking && !m_long_press && m_cursor_press_pos.initialized &&
|
if (!m_prompt_marking && !m_long_press &&
|
||||||
|
m_cursor_press_pos.selection_type == ChatSelection::SELECTION_PROMPT &&
|
||||||
|
m_cursor_press_pos != prompt_cursor_pos) {
|
||||||
|
m_mark_begin = m_cursor_press_pos;
|
||||||
|
m_mark_end = m_cursor_press_pos;
|
||||||
|
m_prompt_marking = true;
|
||||||
|
} else if (!m_history_marking && !m_long_press &&
|
||||||
|
m_cursor_press_pos.selection_type == ChatSelection::SELECTION_HISTORY &&
|
||||||
m_cursor_press_pos != cursor_pos) {
|
m_cursor_press_pos != cursor_pos) {
|
||||||
m_mark_begin = m_cursor_press_pos;
|
m_mark_begin = m_cursor_press_pos;
|
||||||
m_mark_end = m_cursor_press_pos;
|
m_mark_end = m_cursor_press_pos;
|
||||||
m_mouse_marking = true;
|
m_history_marking = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_mouse_marking) {
|
if (m_prompt_marking) {
|
||||||
|
m_mark_end = prompt_cursor_pos;
|
||||||
|
} else if (m_history_marking) {
|
||||||
m_mark_end = cursor_pos;
|
m_mark_end = cursor_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (event.TouchInput.Event == irr::ETIE_PRESSED_LONG) {
|
} else if (event.TouchInput.Event == irr::ETIE_PRESSED_LONG) {
|
||||||
if (!m_mouse_marking) {
|
if (!m_history_marking && ! m_prompt_marking) {
|
||||||
m_long_press = true;
|
m_long_press = true;
|
||||||
if (m_mark_begin != m_mark_end) {
|
if (m_mark_begin != m_mark_end) {
|
||||||
irr::core::stringc text = getSelectedText();
|
irr::core::stringc text;
|
||||||
|
if (m_mark_begin.selection_type == ChatSelection::SELECTION_PROMPT &&
|
||||||
|
m_mark_end.selection_type == ChatSelection::SELECTION_PROMPT) {
|
||||||
|
text = getPromptSelectedText();
|
||||||
|
} else if (m_mark_begin.selection_type == ChatSelection::SELECTION_HISTORY &&
|
||||||
|
m_mark_end.selection_type == ChatSelection::SELECTION_HISTORY) {
|
||||||
|
text = getSelectedText();
|
||||||
|
}
|
||||||
Environment->getOSOperator()->copyToClipboard(text.c_str());
|
Environment->getOSOperator()->copyToClipboard(text.c_str());
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
SDL_AndroidShowToast(
|
SDL_AndroidShowToast(
|
||||||
@ -1041,19 +1423,21 @@ void GUIChatConsole::createVScrollBar()
|
|||||||
addChild(m_vscrollbar);
|
addChild(m_vscrollbar);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIChatConsole::updateVScrollBar()
|
void GUIChatConsole::updateVScrollBar(bool force_update, bool move_bottom)
|
||||||
{
|
{
|
||||||
if (!m_vscrollbar)
|
if (!m_vscrollbar)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ChatBuffer& buf = m_chat_backend->getConsoleBuffer();
|
ChatBuffer& buf = m_chat_backend->getConsoleBuffer();
|
||||||
|
|
||||||
if (m_bottom_scroll_pos != buf.getBottomScrollPos()) {
|
if (m_bottom_scroll_pos != buf.getBottomScrollPos() || force_update) {
|
||||||
|
bool is_bottom = m_vscrollbar->getPos() == m_bottom_scroll_pos;
|
||||||
m_bottom_scroll_pos = buf.getBottomScrollPos();
|
m_bottom_scroll_pos = buf.getBottomScrollPos();
|
||||||
|
|
||||||
if (buf.getBottomScrollPos() > 0) {
|
if (buf.getBottomScrollPos() > 0) {
|
||||||
buf.scrollAbsolute(m_bottom_scroll_pos);
|
buf.scrollAbsolute(m_bottom_scroll_pos);
|
||||||
m_vscrollbar->setMax(m_bottom_scroll_pos);
|
m_vscrollbar->setMax(m_bottom_scroll_pos);
|
||||||
|
if (is_bottom || move_bottom)
|
||||||
m_vscrollbar->setPos(m_bottom_scroll_pos);
|
m_vscrollbar->setPos(m_bottom_scroll_pos);
|
||||||
} else {
|
} else {
|
||||||
m_vscrollbar->setMax(0);
|
m_vscrollbar->setMax(0);
|
||||||
@ -1066,6 +1450,21 @@ void GUIChatConsole::updateVScrollBar()
|
|||||||
m_vscrollbar->setPageSize(page_size);
|
m_vscrollbar->setPageSize(page_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (buf.getDelFormatted() > 0) {
|
||||||
|
bool is_bottom = m_vscrollbar->getPos() == m_bottom_scroll_pos;
|
||||||
|
|
||||||
|
if (!is_bottom && ! move_bottom) {
|
||||||
|
s32 pos = m_vscrollbar->getPos() - buf.getDelFormatted();
|
||||||
|
|
||||||
|
if (pos >= 0)
|
||||||
|
m_vscrollbar->setPos(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_mark_begin.scroll -= buf.getDelFormatted();
|
||||||
|
m_mark_end.scroll -= buf.getDelFormatted();
|
||||||
|
buf.resetDelFormatted();
|
||||||
|
}
|
||||||
|
|
||||||
if (m_vscrollbar->getPos() != buf.getScrollPos()) {
|
if (m_vscrollbar->getPos() != buf.getScrollPos()) {
|
||||||
if (buf.getScrollPos() >= 0) {
|
if (buf.getScrollPos() >= 0) {
|
||||||
s32 deltaScrollY = m_vscrollbar->getPos() - buf.getScrollPos();
|
s32 deltaScrollY = m_vscrollbar->getPos() - buf.getScrollPos();
|
||||||
@ -1081,6 +1480,42 @@ void GUIChatConsole::updateVScrollBar()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GUIChatConsole::onLinesModified()
|
||||||
|
{
|
||||||
|
if (m_mark_begin.selection_type == ChatSelection::SELECTION_HISTORY &&
|
||||||
|
m_mark_end.selection_type == ChatSelection::SELECTION_HISTORY) {
|
||||||
|
|
||||||
|
ChatBuffer& buf = m_chat_backend->getConsoleBuffer();
|
||||||
|
const ChatLine& first_line = buf.getLine(0);
|
||||||
|
int first_line_index = first_line.line_index;
|
||||||
|
|
||||||
|
if (m_mark_begin.line_index < first_line_index ||
|
||||||
|
m_mark_end.line_index < first_line_index) {
|
||||||
|
m_mark_begin.reset();
|
||||||
|
m_mark_end.reset();
|
||||||
|
m_cursor_press_pos.reset();
|
||||||
|
m_history_marking = false;
|
||||||
|
m_long_press = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateVScrollBar(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GUIChatConsole::onPromptModified()
|
||||||
|
{
|
||||||
|
if (m_mark_begin.selection_type == ChatSelection::SELECTION_PROMPT)
|
||||||
|
m_mark_begin.reset();
|
||||||
|
if (m_mark_end.selection_type == ChatSelection::SELECTION_PROMPT)
|
||||||
|
m_mark_end.reset();
|
||||||
|
if (m_cursor_press_pos.selection_type == ChatSelection::SELECTION_PROMPT)
|
||||||
|
m_cursor_press_pos.reset();
|
||||||
|
if (m_prompt_marking) {
|
||||||
|
m_prompt_marking = false;
|
||||||
|
m_long_press = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool GUIChatConsole::hasFocus()
|
bool GUIChatConsole::hasFocus()
|
||||||
{
|
{
|
||||||
if (Environment->hasFocus(this))
|
if (Environment->hasFocus(this))
|
||||||
|
@ -27,14 +27,20 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
struct ChatSelection
|
struct ChatSelection
|
||||||
{
|
{
|
||||||
ChatSelection() : initialized(false), scroll(0), row(0), row_buf(0),
|
enum SelectionType {
|
||||||
line(0), fragment(0), character(0), x_max(false) {};
|
SELECTION_NONE,
|
||||||
|
SELECTION_HISTORY,
|
||||||
|
SELECTION_PROMPT
|
||||||
|
};
|
||||||
|
|
||||||
|
ChatSelection() : selection_type(SELECTION_NONE), scroll(0), row(0),
|
||||||
|
line_index(0), line(0), fragment(0), character(0), x_max(false) {};
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
initialized = false;
|
selection_type = SELECTION_NONE;
|
||||||
scroll = 0;
|
scroll = 0;
|
||||||
row = 0;
|
row = 0;
|
||||||
row_buf = 0;
|
line_index = 0;
|
||||||
line = 0;
|
line = 0;
|
||||||
fragment = 0;
|
fragment = 0;
|
||||||
character = 0;
|
character = 0;
|
||||||
@ -42,19 +48,28 @@ struct ChatSelection
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool operator== (const ChatSelection &other) const {
|
bool operator== (const ChatSelection &other) const {
|
||||||
|
if (selection_type == SELECTION_HISTORY &&
|
||||||
|
other.selection_type == SELECTION_HISTORY) {
|
||||||
return (row + scroll == other.row + other.scroll &&
|
return (row + scroll == other.row + other.scroll &&
|
||||||
row_buf == other.row_buf &&
|
line_index == other.line_index &&
|
||||||
line == other.line &&
|
line == other.line &&
|
||||||
fragment == other.fragment &&
|
fragment == other.fragment &&
|
||||||
character == other.character &&
|
character == other.character &&
|
||||||
x_max == other.x_max);
|
x_max == other.x_max);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return (scroll + character == other.scroll + other.character &&
|
||||||
|
x_max == other.x_max);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator< (const ChatSelection &other) const {
|
bool operator< (const ChatSelection &other) const {
|
||||||
|
if (selection_type == SELECTION_HISTORY &&
|
||||||
|
other.selection_type == SELECTION_HISTORY) {
|
||||||
if (row + scroll != other.row + other.scroll)
|
if (row + scroll != other.row + other.scroll)
|
||||||
return (row + scroll < other.row + other.scroll);
|
return (row + scroll < other.row + other.scroll);
|
||||||
if (row_buf != other.row_buf)
|
if (line_index != other.line_index)
|
||||||
return (row_buf < other.row_buf);
|
return (line_index < other.line_index);
|
||||||
if (line != other.line)
|
if (line != other.line)
|
||||||
return (line < other.line);
|
return (line < other.line);
|
||||||
if (fragment != other.fragment)
|
if (fragment != other.fragment)
|
||||||
@ -65,6 +80,15 @@ struct ChatSelection
|
|||||||
return (x_max < other.x_max);
|
return (x_max < other.x_max);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (scroll + character != other.scroll + other.character)
|
||||||
|
return (scroll + character < other.scroll + other.character);
|
||||||
|
if (x_max != other.x_max)
|
||||||
|
return (x_max < other.x_max);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator> (const ChatSelection &other) {
|
bool operator> (const ChatSelection &other) {
|
||||||
@ -83,10 +107,10 @@ struct ChatSelection
|
|||||||
return !this->operator==(other);
|
return !this->operator==(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool initialized;
|
SelectionType selection_type;
|
||||||
int scroll;
|
int scroll;
|
||||||
int row;
|
int row;
|
||||||
int row_buf;
|
int line_index;
|
||||||
unsigned int line;
|
unsigned int line;
|
||||||
unsigned int fragment;
|
unsigned int fragment;
|
||||||
unsigned int character;
|
unsigned int character;
|
||||||
@ -149,6 +173,9 @@ public:
|
|||||||
bool getAndroidChatOpen() { return m_android_chat_open; }
|
bool getAndroidChatOpen() { return m_android_chat_open; }
|
||||||
void setAndroidChatOpen(bool value) { m_android_chat_open = value; }
|
void setAndroidChatOpen(bool value) { m_android_chat_open = value; }
|
||||||
|
|
||||||
|
void onLinesModified();
|
||||||
|
void onPromptModified();
|
||||||
|
|
||||||
static GUIChatConsole* getChatConsole() { return m_chat_console; }
|
static GUIChatConsole* getChatConsole() { return m_chat_console; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -162,9 +189,14 @@ private:
|
|||||||
void drawPrompt();
|
void drawPrompt();
|
||||||
|
|
||||||
ChatSelection getCursorPos(s32 x, s32 y);
|
ChatSelection getCursorPos(s32 x, s32 y);
|
||||||
|
ChatSelection getPromptCursorPos(s32 x, s32 y);
|
||||||
|
ChatSelection getCurrentPromptCursorPos();
|
||||||
irr::core::stringc getSelectedText();
|
irr::core::stringc getSelectedText();
|
||||||
|
irr::core::stringc getPromptSelectedText();
|
||||||
|
void movePromptCursor(s32 x, s32 y);
|
||||||
|
void deletePromptSelection();
|
||||||
void createVScrollBar();
|
void createVScrollBar();
|
||||||
void updateVScrollBar();
|
void updateVScrollBar(bool force_update = false, bool move_bottom = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static GUIChatConsole* m_chat_console;
|
static GUIChatConsole* m_chat_console;
|
||||||
@ -213,7 +245,8 @@ private:
|
|||||||
|
|
||||||
ChatSelection m_mark_begin;
|
ChatSelection m_mark_begin;
|
||||||
ChatSelection m_mark_end;
|
ChatSelection m_mark_end;
|
||||||
bool m_mouse_marking = false;
|
bool m_history_marking = false;
|
||||||
|
bool m_prompt_marking = false;
|
||||||
bool m_long_press = false;
|
bool m_long_press = false;
|
||||||
ChatSelection m_cursor_press_pos;
|
ChatSelection m_cursor_press_pos;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user