Add text selection and copying to console

This commit is contained in:
ShadowNinja 2016-02-27 16:04:44 -05:00
parent 3edb7575a1
commit 430929e75a
3 changed files with 103 additions and 59 deletions

View File

@ -390,6 +390,7 @@ ChatPrompt::ChatPrompt(std::wstring prompt, u32 history_limit):
m_cols(0), m_cols(0),
m_view(0), m_view(0),
m_cursor(0), m_cursor(0),
m_cursor_len(0),
m_nick_completion_start(0), m_nick_completion_start(0),
m_nick_completion_end(0) m_nick_completion_end(0)
{ {
@ -426,11 +427,6 @@ void ChatPrompt::addToHistory(std::wstring line)
m_history_index = m_history.size(); m_history_index = m_history.size();
} }
std::wstring ChatPrompt::getLine()
{
return m_line;
}
void ChatPrompt::clear() void ChatPrompt::clear()
{ {
m_line.clear(); m_line.clear();
@ -590,14 +586,12 @@ void ChatPrompt::cursorOperation(CursorOp op, CursorOpDir dir, CursorOpScope sco
s32 length = m_line.size(); s32 length = m_line.size();
s32 increment = (dir == CURSOROP_DIR_RIGHT) ? 1 : -1; s32 increment = (dir == CURSOROP_DIR_RIGHT) ? 1 : -1;
if (scope == CURSOROP_SCOPE_CHARACTER) switch (scope) {
{ case CURSOROP_SCOPE_CHARACTER:
new_cursor += increment; new_cursor += increment;
} break;
else if (scope == CURSOROP_SCOPE_WORD) case CURSOROP_SCOPE_WORD:
{ if (dir == CURSOROP_DIR_RIGHT) {
if (increment > 0)
{
// skip one word to the right // skip one word to the right
while (new_cursor < length && isspace(m_line[new_cursor])) while (new_cursor < length && isspace(m_line[new_cursor]))
new_cursor++; new_cursor++;
@ -605,39 +599,47 @@ void ChatPrompt::cursorOperation(CursorOp op, CursorOpDir dir, CursorOpScope sco
new_cursor++; new_cursor++;
while (new_cursor < length && isspace(m_line[new_cursor])) while (new_cursor < length && isspace(m_line[new_cursor]))
new_cursor++; new_cursor++;
} } else {
else
{
// skip one word to the left // skip one word to the left
while (new_cursor >= 1 && isspace(m_line[new_cursor - 1])) while (new_cursor >= 1 && isspace(m_line[new_cursor - 1]))
new_cursor--; new_cursor--;
while (new_cursor >= 1 && !isspace(m_line[new_cursor - 1])) while (new_cursor >= 1 && !isspace(m_line[new_cursor - 1]))
new_cursor--; new_cursor--;
} }
} break;
else if (scope == CURSOROP_SCOPE_LINE) case CURSOROP_SCOPE_LINE:
{
new_cursor += increment * length; new_cursor += increment * length;
break;
case CURSOROP_SCOPE_SELECTION:
break;
} }
new_cursor = MYMAX(MYMIN(new_cursor, length), 0); new_cursor = MYMAX(MYMIN(new_cursor, length), 0);
if (op == CURSOROP_MOVE) switch (op) {
{ case CURSOROP_MOVE:
m_cursor = new_cursor; m_cursor = new_cursor;
} m_cursor_len = 0;
else if (op == CURSOROP_DELETE) break;
{ case CURSOROP_DELETE:
if (new_cursor < old_cursor) if (m_cursor_len > 0) { // Delete selected text first
{ m_line.erase(m_cursor, m_cursor_len);
m_line.erase(new_cursor, old_cursor - new_cursor); } else {
m_cursor = new_cursor; m_cursor = MYMIN(new_cursor, old_cursor);
m_line.erase(m_cursor, abs(new_cursor - old_cursor));
} }
else if (new_cursor > old_cursor) m_cursor_len = 0;
{ break;
m_line.erase(old_cursor, new_cursor - old_cursor); case CURSOROP_SELECT:
m_cursor = old_cursor; if (scope == CURSOROP_SCOPE_LINE) {
m_cursor = 0;
m_cursor_len = length;
} else {
m_cursor = MYMIN(new_cursor, old_cursor);
m_cursor_len += abs(new_cursor - old_cursor);
m_cursor_len = MYMIN(m_cursor_len, length - m_cursor);
} }
break;
} }
clampView(); clampView();

View File

@ -150,7 +150,11 @@ public:
void addToHistory(std::wstring line); void addToHistory(std::wstring line);
// Get current line // Get current line
std::wstring getLine(); std::wstring getLine() const { return m_line; }
// Get section of line that is currently selected
std::wstring getSelection() const
{ return m_line.substr(m_cursor, m_cursor_len); }
// Clear the current line // Clear the current line
void clear(); void clear();
@ -172,10 +176,13 @@ 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 length of cursor selection
s32 getCursorLength() const { return m_cursor_len; }
// Cursor operations // Cursor operations
enum CursorOp { enum CursorOp {
CURSOROP_MOVE, CURSOROP_MOVE,
CURSOROP_SELECT,
CURSOROP_DELETE CURSOROP_DELETE
}; };
@ -189,7 +196,8 @@ public:
enum CursorOpScope { enum CursorOpScope {
CURSOROP_SCOPE_CHARACTER, CURSOROP_SCOPE_CHARACTER,
CURSOROP_SCOPE_WORD, CURSOROP_SCOPE_WORD,
CURSOROP_SCOPE_LINE CURSOROP_SCOPE_LINE,
CURSOROP_SCOPE_SELECTION
}; };
// Cursor operation // Cursor operation
@ -227,6 +235,8 @@ private:
s32 m_view; s32 m_view;
// Cursor (index into m_line) // Cursor (index into m_line)
s32 m_cursor; s32 m_cursor;
// Cursor length (length of selected portion of line)
s32 m_cursor_len;
// Last nick completion start (index into m_line) // Last nick completion start (index into m_line)
s32 m_nick_completion_start; s32 m_nick_completion_start;

View File

@ -377,13 +377,15 @@ void GUIChatConsole::drawPrompt()
s32 cursor_pos = prompt.getVisibleCursorPosition(); s32 cursor_pos = prompt.getVisibleCursorPosition();
if (cursor_pos >= 0) if (cursor_pos >= 0)
{ {
s32 cursor_len = prompt.getCursorLength();
video::IVideoDriver* driver = Environment->getVideoDriver(); video::IVideoDriver* driver = Environment->getVideoDriver();
s32 x = (1 + cursor_pos) * m_fontsize.X; s32 x = (1 + cursor_pos) * m_fontsize.X;
core::rect<s32> destrect( core::rect<s32> destrect(
x, x,
y + (1.0-m_cursor_height) * m_fontsize.Y, y + m_fontsize.Y * (1.0 - m_cursor_height),
x + m_fontsize.X, x + m_fontsize.X * MYMAX(cursor_len, 1),
y + m_fontsize.Y); y + m_fontsize.Y * (cursor_len ? m_cursor_height+1 : 1)
);
video::SColor cursor_color(255,255,255,255); video::SColor cursor_color(255,255,255,255);
driver->draw2DRectangle( driver->draw2DRectangle(
cursor_color, cursor_color,
@ -454,32 +456,20 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
prompt.historyNext(); prompt.historyNext();
return true; return true;
} }
else if(event.KeyInput.Key == KEY_LEFT) else if(event.KeyInput.Key == KEY_LEFT || event.KeyInput.Key == KEY_RIGHT)
{ {
// Left or Ctrl-Left pressed // Left/right pressed
// move character / word to the left // Move/select character/word to the left depending on control and shift keys
ChatPrompt::CursorOpScope scope = ChatPrompt::CursorOp op = event.KeyInput.Shift ?
event.KeyInput.Control ? ChatPrompt::CURSOROP_SELECT :
ChatPrompt::CURSOROP_MOVE;
ChatPrompt::CursorOpDir dir = event.KeyInput.Key == KEY_LEFT ?
ChatPrompt::CURSOROP_DIR_LEFT :
ChatPrompt::CURSOROP_DIR_RIGHT;
ChatPrompt::CursorOpScope scope = event.KeyInput.Control ?
ChatPrompt::CURSOROP_SCOPE_WORD : ChatPrompt::CURSOROP_SCOPE_WORD :
ChatPrompt::CURSOROP_SCOPE_CHARACTER; ChatPrompt::CURSOROP_SCOPE_CHARACTER;
prompt.cursorOperation( prompt.cursorOperation(op, dir, scope);
ChatPrompt::CURSOROP_MOVE,
ChatPrompt::CURSOROP_DIR_LEFT,
scope);
return true;
}
else if(event.KeyInput.Key == KEY_RIGHT)
{
// Right or Ctrl-Right pressed
// move character / word to the right
ChatPrompt::CursorOpScope scope =
event.KeyInput.Control ?
ChatPrompt::CURSOROP_SCOPE_WORD :
ChatPrompt::CURSOROP_SCOPE_CHARACTER;
prompt.cursorOperation(
ChatPrompt::CURSOROP_MOVE,
ChatPrompt::CURSOROP_DIR_RIGHT,
scope);
return true; return true;
} }
else if(event.KeyInput.Key == KEY_HOME) else if(event.KeyInput.Key == KEY_HOME)
@ -530,16 +520,58 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
scope); scope);
return true; return true;
} }
else if(event.KeyInput.Key == KEY_KEY_A && event.KeyInput.Control)
{
// Ctrl-A pressed
// Select all text
prompt.cursorOperation(
ChatPrompt::CURSOROP_SELECT,
ChatPrompt::CURSOROP_DIR_LEFT, // Ignored
ChatPrompt::CURSOROP_SCOPE_LINE);
return true;
}
else if(event.KeyInput.Key == KEY_KEY_C && event.KeyInput.Control)
{
// Ctrl-C pressed
// Copy text to clipboard
if (prompt.getCursorLength() <= 0)
return true;
std::string selected = wide_to_narrow(prompt.getSelection());
Environment->getOSOperator()->copyToClipboard(selected.c_str());
return true;
}
else if(event.KeyInput.Key == KEY_KEY_V && event.KeyInput.Control) else if(event.KeyInput.Key == KEY_KEY_V && event.KeyInput.Control)
{ {
// Ctrl-V pressed // Ctrl-V pressed
// paste text from clipboard // paste text from clipboard
if (prompt.getCursorLength() > 0) {
// Delete selected section of text
prompt.cursorOperation(
ChatPrompt::CURSOROP_DELETE,
ChatPrompt::CURSOROP_DIR_LEFT, // Ignored
ChatPrompt::CURSOROP_SCOPE_SELECTION);
}
IOSOperator *os_operator = Environment->getOSOperator(); IOSOperator *os_operator = Environment->getOSOperator();
const c8 *text = os_operator->getTextFromClipboard(); const c8 *text = os_operator->getTextFromClipboard();
if (text) if (text)
prompt.input(narrow_to_wide(text)); prompt.input(narrow_to_wide(text));
return true; return true;
} }
else if(event.KeyInput.Key == KEY_KEY_X && event.KeyInput.Control)
{
// Ctrl-X pressed
// Cut text to clipboard
if (prompt.getCursorLength() <= 0)
return true;
std::wstring wselected = prompt.getSelection();
std::string selected(wselected.begin(), wselected.end());
Environment->getOSOperator()->copyToClipboard(selected.c_str());
prompt.cursorOperation(
ChatPrompt::CURSOROP_DELETE,
ChatPrompt::CURSOROP_DIR_LEFT, // Ignored
ChatPrompt::CURSOROP_SCOPE_SELECTION);
return true;
}
else if(event.KeyInput.Key == KEY_KEY_U && event.KeyInput.Control) else if(event.KeyInput.Key == KEY_KEY_U && event.KeyInput.Control)
{ {
// Ctrl-U pressed // Ctrl-U pressed