Browse Source

Use cursor and selection for index positions instead of begin and end

for TextField
tags/v0.6.0
Andrew Belt 6 years ago
parent
commit
d392b424d2
4 changed files with 97 additions and 74 deletions
  1. +6
    -3
      include/ui.hpp
  2. +2
    -2
      include/util/math.hpp
  3. +3
    -2
      src/app/LedDisplay.cpp
  4. +86
    -67
      src/ui/TextField.cpp

+ 6
- 3
include/ui.hpp View File

@@ -193,9 +193,12 @@ struct TextField : OpaqueWidget {
std::string text;
std::string placeholder;
bool multiline = false;
int begin = 0;
int end = 0;
int dragPos = 0;
/** The index of the text cursor */
int cursor = 0;
/** The index of the other end of the selection.
If nothing is selected, this is equal to `cursor`.
*/
int selection = 0;

TextField() {
box.size.y = BND_WIDGET_HEIGHT;


+ 2
- 2
include/util/math.hpp View File

@@ -14,7 +14,7 @@ using std::isnormal;
namespace rack {

////////////////////
// basic integer functions (suffixed with "i")
// basic integer functions
////////////////////

inline int min(int a, int b) {
@@ -54,7 +54,7 @@ inline bool ispow2(int n) {
}

////////////////////
// basic float functions (suffixed with "f")
// basic float functions
////////////////////

/** Returns 1.f for positive numbers and -1.f for negative numbers (including positive/negative zero) */


+ 3
- 2
src/app/LedDisplay.cpp View File

@@ -84,10 +84,11 @@ void LedDisplayTextField::draw(NVGcontext *vg) {

NVGcolor highlightColor = color;
highlightColor.a = 0.5;
int cend = (this == gFocusedWidget) ? end : -1;
int begin = min(cursor, selection);
int end = (this == gFocusedWidget) ? max(cursor, selection) : -1;
bndIconLabelCaret(vg, textOffset.x, textOffset.y,
box.size.x - 2*textOffset.x, box.size.y - 2*textOffset.y,
-1, color, 12, text.c_str(), highlightColor, begin, cend);
-1, color, 12, text.c_str(), highlightColor, begin, end);

bndSetFont(gGuiFont->handle);
}


+ 86
- 67
src/ui/TextField.cpp View File

@@ -19,6 +19,8 @@ void TextField::draw(NVGcontext *vg) {
else
state = BND_DEFAULT;

int begin = min(cursor, selection);
int end = max(cursor, selection);
bndTextField(vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE, state, -1, text.c_str(), begin, end);
// Draw placeholder text
if (text.empty() && state != BND_ACTIVE) {
@@ -29,25 +31,24 @@ void TextField::draw(NVGcontext *vg) {
}

void TextField::onMouseDown(EventMouseDown &e) {
dragPos = getTextPosition(e.pos);
begin = end = dragPos;
debug("%d", this == gFocusedWidget);
if (e.button == 0) {
cursor = selection = getTextPosition(e.pos);
}
OpaqueWidget::onMouseDown(e);
}

void TextField::onMouseMove(EventMouseMove &e) {
if (this == gDraggedWidget) {
int pos = getTextPosition(e.pos);
if (pos != dragPos) {
begin = min(dragPos, pos);
end = max(dragPos, pos);
if (pos != selection) {
cursor = pos;
}
}
OpaqueWidget::onMouseMove(e);
}

void TextField::onFocus(EventFocus &e) {
begin = 0;
end = text.size();
e.consumed = true;
}

@@ -61,85 +62,101 @@ void TextField::onText(EventText &e) {

void TextField::onKey(EventKey &e) {
switch (e.key) {
case GLFW_KEY_BACKSPACE:
if (begin < end) {
text.erase(begin, end - begin);
onTextChange();
}
else {
begin--;
if (begin >= 0) {
text.erase(begin, 1);
case GLFW_KEY_BACKSPACE: {
if (cursor == selection) {
cursor--;
if (cursor >= 0) {
text.erase(cursor, 1);
onTextChange();
}
selection = cursor;
}
end = begin;
break;
case GLFW_KEY_DELETE:
if (begin < end) {
text.erase(begin, end - begin);
else {
int begin = min(cursor, selection);
text.erase(begin, std::abs(selection - cursor));
onTextChange();
cursor = selection = begin;
}
} break;
case GLFW_KEY_DELETE: {
if (cursor == selection) {
text.erase(cursor, 1);
onTextChange();
}
else {
text.erase(begin, 1);
int begin = min(cursor, selection);
text.erase(begin, std::abs(selection - cursor));
onTextChange();
cursor = selection = begin;
}
end = begin;
break;
case GLFW_KEY_LEFT:
if (begin < end) {
} break;
case GLFW_KEY_LEFT: {
if (windowIsModPressed()) {
while (--cursor > 0) {
if (text[cursor] == ' ')
break;
}
}
else {
begin--;
cursor--;
}
if (!windowIsShiftPressed()) {
selection = cursor;
}
end = begin;
break;
case GLFW_KEY_RIGHT:
if (begin < end) {
begin = end;
} break;
case GLFW_KEY_RIGHT: {
if (windowIsModPressed()) {
while (++cursor < (int) text.size()) {
if (text[cursor] == ' ')
break;
}
}
else {
begin++;
}
end = begin;
break;
case GLFW_KEY_HOME:
end = begin = 0;
break;
case GLFW_KEY_END:
end = begin = text.size();
break;
case GLFW_KEY_V:
cursor++;
}
if (!windowIsShiftPressed()) {
selection = cursor;
}
} break;
case GLFW_KEY_HOME: {
selection = cursor = 0;
} break;
case GLFW_KEY_END: {
selection = cursor = text.size();
} break;
case GLFW_KEY_V: {
if (windowIsModPressed()) {
const char *newText = glfwGetClipboardString(gWindow);
if (newText)
insertText(newText);
}
break;
case GLFW_KEY_X:
} break;
case GLFW_KEY_X: {
if (windowIsModPressed()) {
if (begin < end) {
std::string selectedText = text.substr(begin, end - begin);
if (cursor != selection) {
int begin = min(cursor, selection);
std::string selectedText = text.substr(begin, std::abs(selection - cursor));
glfwSetClipboardString(gWindow, selectedText.c_str());
insertText("");
}
}
break;
case GLFW_KEY_C:
} break;
case GLFW_KEY_C: {
if (windowIsModPressed()) {
if (begin < end) {
std::string selectedText = text.substr(begin, end - begin);
if (cursor != selection) {
int begin = min(cursor, selection);
std::string selectedText = text.substr(begin, std::abs(selection - cursor));
glfwSetClipboardString(gWindow, selectedText.c_str());
}
}
break;
case GLFW_KEY_A:
} break;
case GLFW_KEY_A: {
if (windowIsModPressed()) {
begin = 0;
end = text.size();
selection = 0;
cursor = text.size();
}
break;
case GLFW_KEY_ENTER:
} break;
case GLFW_KEY_ENTER: {
if (multiline) {
insertText("\n");
}
@@ -147,27 +164,29 @@ void TextField::onKey(EventKey &e) {
EventAction e;
onAction(e);
}
break;
} break;
}

begin = clamp(begin, 0, text.size());
end = clamp(end, 0, text.size());
cursor = clamp(cursor, 0, text.size());
selection = clamp(selection, 0, text.size());
e.consumed = true;
}

void TextField::insertText(std::string text) {
if (begin < end)
this->text.erase(begin, end - begin);
this->text.insert(begin, text);
begin += text.size();
end = begin;
if (cursor != selection) {
int begin = min(cursor, selection);
this->text.erase(begin, std::abs(selection - cursor));
cursor = selection = begin;
}
this->text.insert(cursor, text);
cursor += text.size();
selection = cursor;
onTextChange();
}

void TextField::setText(std::string text) {
this->text = text;
begin = clamp(begin, 0, text.size());
end = clamp(end, 0, text.size());
selection = cursor = text.size();
onTextChange();
}



Loading…
Cancel
Save