mirror of
https://github.com/minetest/minetest.git
synced 2025-01-12 08:17:31 +01:00
Add text selection and copying to console
This commit is contained in:
parent
3edb7575a1
commit
430929e75a
64
src/chat.cpp
64
src/chat.cpp
@ -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();
|
||||||
|
14
src/chat.h
14
src/chat.h
@ -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;
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user