[LLDB][GUI] Add extra keys to text field

This patch adds many new keys to the text field and implements new
behaviors as follows:

```
case KEY_HOME:
case KEY_CTRL_A:
  MoveCursorToStart();
case KEY_END:
case KEY_CTRL_E:
  MoveCursorToEnd();
case KEY_RIGHT:
case KEY_SF:
  MoveCursorRight();
case KEY_LEFT:
case KEY_SR:
  MoveCursorLeft();
case KEY_BACKSPACE:
case KEY_DELETE:
  RemovePreviousChar();
case KEY_DC:
  RemoveNextChar();
case KEY_EOL:
case KEY_CTRL_K:
  ClearToEnd();
case KEY_DL:
case KEY_CLEAR:
  Clear();
```

This patch also refactors scrolling to be dynamic at draw time for
easier handing.

Differential Revision: https://reviews.llvm.org/D108385
This commit is contained in:
Omar Emara 2021-08-19 11:47:07 -07:00 committed by Greg Clayton
parent c728bd5bba
commit d95d2a8e4a
1 changed files with 75 additions and 26 deletions

View File

@ -85,8 +85,12 @@ using llvm::StringRef;
// we may want curses to be disabled for some builds for instance, windows // we may want curses to be disabled for some builds for instance, windows
#if LLDB_ENABLE_CURSES #if LLDB_ENABLE_CURSES
#define KEY_CTRL_A 1
#define KEY_CTRL_E 5
#define KEY_CTRL_K 11
#define KEY_RETURN 10 #define KEY_RETURN 10
#define KEY_ESCAPE 27 #define KEY_ESCAPE 27
#define KEY_DELETE 127
#define KEY_SHIFT_TAB (KEY_MAX + 1) #define KEY_SHIFT_TAB (KEY_MAX + 1)
@ -1106,10 +1110,11 @@ public:
int GetContentLength() { return m_content.length(); } int GetContentLength() { return m_content.length(); }
void DrawContent(Surface &surface, bool is_selected) { void DrawContent(Surface &surface, bool is_selected) {
UpdateScrolling(surface.GetWidth());
surface.MoveCursor(0, 0); surface.MoveCursor(0, 0);
const char *text = m_content.c_str() + m_first_visibile_char; const char *text = m_content.c_str() + m_first_visibile_char;
surface.PutCString(text, surface.GetWidth()); surface.PutCString(text, surface.GetWidth());
m_last_drawn_content_width = surface.GetWidth();
// Highlight the cursor. // Highlight the cursor.
surface.MoveCursor(GetCursorXPosition(), 0); surface.MoveCursor(GetCursorXPosition(), 0);
@ -1156,6 +1161,22 @@ public:
DrawError(error_surface); DrawError(error_surface);
} }
// Get the position of the last visible character.
int GetLastVisibleCharPosition(int width) {
int position = m_first_visibile_char + width - 1;
return std::min(position, GetContentLength());
}
void UpdateScrolling(int width) {
if (m_cursor_position < m_first_visibile_char) {
m_first_visibile_char = m_cursor_position;
return;
}
if (m_cursor_position > GetLastVisibleCharPosition(width))
m_first_visibile_char = m_cursor_position - (width - 1);
}
// The cursor is allowed to move one character past the string. // The cursor is allowed to move one character past the string.
// m_cursor_position is in range [0, GetContentLength()]. // m_cursor_position is in range [0, GetContentLength()].
void MoveCursorRight() { void MoveCursorRight() {
@ -1168,42 +1189,54 @@ public:
m_cursor_position--; m_cursor_position--;
} }
// If the cursor moved past the last visible character, scroll right by one void MoveCursorToStart() { m_cursor_position = 0; }
// character.
void ScrollRightIfNeeded() { void MoveCursorToEnd() { m_cursor_position = GetContentLength(); }
if (m_cursor_position - m_first_visibile_char == m_last_drawn_content_width)
m_first_visibile_char++;
}
void ScrollLeft() { void ScrollLeft() {
if (m_first_visibile_char > 0) if (m_first_visibile_char > 0)
m_first_visibile_char--; m_first_visibile_char--;
} }
// If the cursor moved past the first visible character, scroll left by one // Insert a character at the current cursor position and advance the cursor
// character. // position.
void ScrollLeftIfNeeded() {
if (m_cursor_position < m_first_visibile_char)
m_first_visibile_char--;
}
// Insert a character at the current cursor position, advance the cursor
// position, and make sure to scroll right if needed.
void InsertChar(char character) { void InsertChar(char character) {
m_content.insert(m_cursor_position, 1, character); m_content.insert(m_cursor_position, 1, character);
m_cursor_position++; m_cursor_position++;
ScrollRightIfNeeded(); ClearError();
} }
// Remove the character before the cursor position, retreat the cursor // Remove the character before the cursor position, retreat the cursor
// position, and make sure to scroll left if needed. // position, and scroll left.
void RemoveChar() { void RemovePreviousChar() {
if (m_cursor_position == 0) if (m_cursor_position == 0)
return; return;
m_content.erase(m_cursor_position - 1, 1); m_content.erase(m_cursor_position - 1, 1);
m_cursor_position--; m_cursor_position--;
ScrollLeft(); ScrollLeft();
ClearError();
}
// Remove the character after the cursor position.
void RemoveNextChar() {
if (m_cursor_position == GetContentLength())
return;
m_content.erase(m_cursor_position, 1);
ClearError();
}
// Clear characters from the current cursor position to the end.
void ClearToEnd() {
m_content.erase(m_cursor_position);
ClearError();
}
void Clear() {
m_content.clear();
m_cursor_position = 0;
ClearError();
} }
// True if the key represents a char that can be inserted in the field // True if the key represents a char that can be inserted in the field
@ -1224,17 +1257,36 @@ public:
} }
switch (key) { switch (key) {
case KEY_HOME:
case KEY_CTRL_A:
MoveCursorToStart();
return eKeyHandled;
case KEY_END:
case KEY_CTRL_E:
MoveCursorToEnd();
return eKeyHandled;
case KEY_RIGHT: case KEY_RIGHT:
case KEY_SF:
MoveCursorRight(); MoveCursorRight();
ScrollRightIfNeeded();
return eKeyHandled; return eKeyHandled;
case KEY_LEFT: case KEY_LEFT:
case KEY_SR:
MoveCursorLeft(); MoveCursorLeft();
ScrollLeftIfNeeded();
return eKeyHandled; return eKeyHandled;
case KEY_BACKSPACE: case KEY_BACKSPACE:
ClearError(); case KEY_DELETE:
RemoveChar(); RemovePreviousChar();
return eKeyHandled;
case KEY_DC:
RemoveNextChar();
return eKeyHandled;
case KEY_EOL:
case KEY_CTRL_K:
ClearToEnd();
return eKeyHandled;
case KEY_DL:
case KEY_CLEAR:
Clear();
return eKeyHandled; return eKeyHandled;
default: default:
break; break;
@ -1277,9 +1329,6 @@ protected:
int m_cursor_position; int m_cursor_position;
// The index of the first visible character in the content. // The index of the first visible character in the content.
int m_first_visibile_char; int m_first_visibile_char;
// The width of the fields content that was last drawn. Width can change, so
// this is used to determine if scrolling is needed dynamically.
int m_last_drawn_content_width;
// Optional error message. If empty, field is considered to have no error. // Optional error message. If empty, field is considered to have no error.
std::string m_error; std::string m_error;
}; };