aboutsummaryrefslogtreecommitdiff
path: root/src/Text.cpp
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2020-09-29 01:13:00 +0200
committerdec05eba <dec05eba@protonmail.com>2020-09-29 01:13:00 +0200
commitf92ac0050ffcc4b85b116602d4a45344b7e86f52 (patch)
tree8c90bfd5c90f3992319b2653be4d8793456cdb24 /src/Text.cpp
parent4b00d02b124070064b0a8cbd3a8178c599a2a88c (diff)
Fix caret navigation
Diffstat (limited to 'src/Text.cpp')
-rw-r--r--src/Text.cpp210
1 files changed, 114 insertions, 96 deletions
diff --git a/src/Text.cpp b/src/Text.cpp
index 3962374..5e0ad87 100644
--- a/src/Text.cpp
+++ b/src/Text.cpp
@@ -42,7 +42,8 @@ namespace QuickMedia
caretMoveDirection(CaretMoveDirection::NONE),
lineSpacing(0.0f),
characterSpacing(0.0f),
- caretIndex(0)
+ caretIndex(0),
+ caret_offset_x(0.0f)
{
vertices[0].setPrimitiveType(sf::PrimitiveType::Quads);
vertices[1].setPrimitiveType(sf::PrimitiveType::Quads);
@@ -229,6 +230,39 @@ namespace QuickMedia
float Text::get_text_quad_right_side(const VertexRef &vertex_ref) const {
return vertices[vertex_ref.vertices_index][vertex_ref.index + 1].position.x;
}
+
+ float Text::get_caret_offset_by_caret_index(int index) const {
+ const int num_vertices = vertices_linear.size();
+ if(num_vertices == 0)
+ return 0.0f;
+ else if(index < num_vertices)
+ return get_text_quad_left_side(vertices_linear[index]);
+ else
+ return get_text_quad_right_side(vertices_linear[num_vertices - 1]);
+ }
+
+ VertexRef& Text::get_vertex_ref_clamp(int index) {
+ const int num_vertices = vertices_linear.size();
+ assert(num_vertices > 0);
+ if(index == num_vertices)
+ return vertices_linear.back();
+ else
+ return vertices_linear[index];
+ }
+
+ int Text::get_vertex_line(int index) const {
+ const int num_vertices = vertices_linear.size();
+ if(num_vertices == 0) {
+ return 0;
+ } else if(index < num_vertices) {
+ return vertices_linear[index].line;
+ } else {
+ if(vertices_linear.back().codepoint == '\n')
+ return vertices_linear.back().line + 1;
+ else
+ return vertices_linear.back().line;
+ }
+ }
void Text::updateGeometry(bool update_even_if_not_dirty) {
if(dirtyText) {
@@ -299,12 +333,12 @@ namespace QuickMedia
}
case '\n':
{
+ vertices[vertices_index][vertexStart + 0] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() };
+ vertices[vertices_index][vertexStart + 1] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() };
+ vertices[vertices_index][vertexStart + 2] = { sf::Vector2f(glyphPos.x, glyphPos.y), sf::Color::Transparent, sf::Vector2f() };
+ vertices[vertices_index][vertexStart + 3] = { sf::Vector2f(glyphPos.x, glyphPos.y), sf::Color::Transparent, sf::Vector2f() };
glyphPos.x = 0.0f;
glyphPos.y += floor(vspace + lineSpacing);
- vertices[vertices_index][vertexStart + 0] = { sf::Vector2f(0.0f, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() };
- vertices[vertices_index][vertexStart + 1] = { sf::Vector2f(0.0f, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() };
- vertices[vertices_index][vertexStart + 2] = { sf::Vector2f(0.0f, glyphPos.y), sf::Color::Transparent, sf::Vector2f() };
- vertices[vertices_index][vertexStart + 3] = { sf::Vector2f(0.0f, glyphPos.y), sf::Color::Transparent, sf::Vector2f() };
vertices_linear.push_back({vertices_index, vertexStart, 0, codePoint});
continue;
}
@@ -349,6 +383,19 @@ namespace QuickMedia
// TODO: Binary search?
for(int i = 0; i < (int)vertices_linear.size(); ++i) {
VertexRef &vertex_ref = vertices_linear[i];
+
+ sf::Vertex *vertex = &vertices[vertex_ref.vertices_index][vertex_ref.index];
+ vertex[0].position.x -= text_wrap_offset;
+ vertex[1].position.x -= text_wrap_offset;
+ vertex[2].position.x -= text_wrap_offset;
+ vertex[3].position.x -= text_wrap_offset;
+
+ vertex[0].position.y += text_offset_y;
+ vertex[1].position.y += text_offset_y;
+ vertex[2].position.y += text_offset_y;
+ vertex[3].position.y += text_offset_y;
+ vertex_ref.line = num_lines - 1;
+
switch(vertex_ref.codepoint) {
case ' ':
case '\t':
@@ -363,18 +410,6 @@ namespace QuickMedia
break;
}
- sf::Vertex *vertex = &vertices[vertex_ref.vertices_index][vertex_ref.index];
- vertex[0].position.x -= text_wrap_offset;
- vertex[1].position.x -= text_wrap_offset;
- vertex[2].position.x -= text_wrap_offset;
- vertex[3].position.x -= text_wrap_offset;
-
- vertex[0].position.y += text_offset_y;
- vertex[1].position.y += text_offset_y;
- vertex[2].position.y += text_offset_y;
- vertex[3].position.y += text_offset_y;
- vertex_ref.line = num_lines - 1;
-
float vertex_right_side = get_text_quad_right_side(vertex_ref);
if(vertex_right_side > maxWidth) {
++num_lines;
@@ -423,58 +458,65 @@ namespace QuickMedia
}
boundingBox.height = num_lines * line_height;
dirty = false;
+
+ // TODO: Clear vertices_linear when not in edit mode, but take into consideration switching between edit/not-edit mode
}
- // TODO: Fix caret up/down navigation! its broken because of newlines
void Text::updateCaret()
{
assert(!dirty && !dirtyText);
if(vertices_linear.empty()) {
caretIndex = 0;
caretPosition = sf::Vector2f(0.0f, floor(font->getLineSpacing(characterSize)));
+ caret_offset_x = 0.0f;
return;
}
- switch(caretMoveDirection)
- {
- case CaretMoveDirection::UP:
- {
+ switch(caretMoveDirection) {
+ case CaretMoveDirection::NONE: {
+ caret_offset_x = get_caret_offset_by_caret_index(caretIndex);
+ break;
+ }
+ case CaretMoveDirection::UP: {
caretIndex = getPreviousLineClosestPosition(caretIndex);
break;
}
- case CaretMoveDirection::DOWN:
- {
+ case CaretMoveDirection::DOWN: {
caretIndex = getNextLineClosestPosition(caretIndex);
break;
}
- case CaretMoveDirection::HOME:
- {
+ case CaretMoveDirection::HOME: {
caretIndex = getStartOfLine(caretIndex);
+ caret_offset_x = get_caret_offset_by_caret_index(caretIndex);
break;
}
- case CaretMoveDirection::END:
- {
+ case CaretMoveDirection::END: {
caretIndex = getEndOfLine(caretIndex);
+ caret_offset_x = get_caret_offset_by_caret_index(caretIndex);
+ break;
+ }
+ case CaretMoveDirection::LEFT: {
+ caretIndex = std::max(0, caretIndex - 1);
+ caret_offset_x = get_caret_offset_by_caret_index(caretIndex);
break;
}
- case CaretMoveDirection::NONE:
- // Ignore...
+ case CaretMoveDirection::RIGHT: {
+ caretIndex = std::min((int)vertices_linear.size(), caretIndex + 1);
+ caret_offset_x = get_caret_offset_by_caret_index(caretIndex);
break;
+ }
}
if(caretIndex == (int)vertices_linear.size()) {
- caretPosition.x = get_text_quad_right_side(vertices_linear.back());
- caretPosition.y = (1 + vertices_linear.back().line) * floor(font->getLineSpacing(characterSize) + lineSpacing);
- } else if(caretIndex == 0) {
- caretPosition = sf::Vector2f(0.0f, floor(font->getLineSpacing(characterSize)));
+ VertexRef &last_vertex = get_vertex_ref_clamp(caretIndex);
+ if(last_vertex.codepoint == '\n')
+ caretPosition.x = 0.0f;
+ else
+ caretPosition.x = get_text_quad_right_side(last_vertex);
+ caretPosition.y = (1 + get_vertex_line(caretIndex)) * floor(font->getLineSpacing(characterSize) + lineSpacing);
} else {
- if(vertices_linear[caretIndex].codepoint == '\n') {
- caretPosition.x = get_text_quad_right_side(vertices_linear[caretIndex - 1]);
- caretPosition.y = (1 + vertices_linear[caretIndex - 1].line) * floor(font->getLineSpacing(characterSize) + lineSpacing);
- } else {
- caretPosition.x = get_text_quad_left_side(vertices_linear[caretIndex]);
- caretPosition.y = (1 + vertices_linear[caretIndex].line) * floor(font->getLineSpacing(characterSize) + lineSpacing);
- }
+ caretPosition.x = get_caret_offset_by_caret_index(caretIndex);
+ caretPosition.y = (1 + get_vertex_line(caretIndex)) * floor(font->getLineSpacing(characterSize) + lineSpacing);
}
}
@@ -482,15 +524,9 @@ namespace QuickMedia
int Text::getStartOfLine(int startIndex) const
{
assert(!dirty && !dirtyText);
- const int num_vertices = vertices_linear.size();
- const int start_index_wrap = startIndex < num_vertices ? startIndex : num_vertices - 1;
- int start_line = vertices_linear[start_index_wrap].line;
- if(vertices_linear[start_index_wrap].codepoint == '\n')
- --start_line;
+ int start_line = get_vertex_line(startIndex);
for(int i = startIndex - 1; i >= 0; --i) {
- if(vertices_linear[i].line != start_line) {
- if(i + 2 <= num_vertices && vertices_linear[i + 1].codepoint == '\n')
- return i + 2;
+ if(get_vertex_line(i) != start_line) {
return i + 1;
}
}
@@ -502,45 +538,32 @@ namespace QuickMedia
{
assert(!dirty && !dirtyText);
const int num_vertices = vertices_linear.size();
- const int start_index_wrap = startIndex < num_vertices ? startIndex : num_vertices - 1;
- int start_line = vertices_linear[start_index_wrap].line;
- if(vertices_linear[start_index_wrap].codepoint == '\n')
- return startIndex;
- for(int i = startIndex + 1; i < (int)vertices_linear.size(); ++i) {
- if(vertices_linear[i].line != start_line) {
- if(vertices_linear[i].codepoint == '\n')
- return i;
+ int start_line = get_vertex_line(startIndex);
+ for(int i = startIndex + 1; i < num_vertices; ++i) {
+ if(get_vertex_line(i) != start_line) {
return i - 1;
}
}
- return (int)vertices_linear.size();
+ return num_vertices;
}
// TODO: This can be optimized by using binary search
int Text::getPreviousLineClosestPosition(int startIndex) const
{
assert(!dirty && !dirtyText);
- const int num_vertices = vertices_linear.size();
- float start_left_pos;
- if(startIndex == num_vertices) {
- start_left_pos = get_text_quad_right_side(vertices_linear.back());
- if(vertices_linear.back().codepoint == '\n')
- return getStartOfLine(startIndex - 1);
- } else {
- start_left_pos = get_text_quad_left_side(vertices_linear[startIndex]);
- if(vertices_linear[startIndex].codepoint == '\n')
- return getStartOfLine(startIndex - 1);
- }
+ const int start_line = get_vertex_line(startIndex);
float closest_char = 999999.9f;
- for(int i = getStartOfLine(startIndex) - 1; i >= 0; --i) {
- //if(vertices_linear[i].codepoint == '\n')
- // continue;
+ int closest_index = -1;
+ for(int i = getStartOfLine(startIndex) - 1; i >= 0 && get_vertex_line(i) == start_line - 1; --i) {
const float left_pos = get_text_quad_left_side(vertices_linear[i]);
- const float pos_diff = std::abs(start_left_pos - left_pos);
- if(pos_diff > closest_char)
- return i + 1;
- closest_char = pos_diff;
+ const float pos_diff = std::abs(caret_offset_x - left_pos);
+ if(pos_diff < closest_char) {
+ closest_char = pos_diff;
+ closest_index = i;
+ }
}
+ if(closest_index != -1)
+ return closest_index;
return 0;
}
@@ -549,25 +572,20 @@ namespace QuickMedia
{
assert(!dirty && !dirtyText);
const int num_vertices = vertices_linear.size();
- float start_left_pos;
- if(startIndex == num_vertices) {
- return startIndex;
- } else {
- start_left_pos = get_text_quad_left_side(vertices_linear[startIndex]);
- if(vertices_linear[startIndex].codepoint == '\n')
- return startIndex + 1;
- }
+ const int start_line = get_vertex_line(startIndex);
float closest_char = 999999.9f;
- for(int i = getEndOfLine(startIndex) + 1; i < (int)vertices_linear.size(); ++i) {
- //if(vertices_linear[i].codepoint == '\n')
- // continue;
+ int closest_index = -1;
+ for(int i = getEndOfLine(startIndex) + 1; i < num_vertices && get_vertex_line(i) == start_line + 1; ++i) {
const float left_pos = get_text_quad_left_side(vertices_linear[i]);
- const float pos_diff = std::abs(start_left_pos - left_pos);
- if(pos_diff > closest_char)
- return i - 1;
- closest_char = pos_diff;
+ const float pos_diff = std::abs(caret_offset_x - left_pos);
+ if(pos_diff < closest_char) {
+ closest_char = pos_diff;
+ closest_index = i;
+ }
}
- return (int)vertices_linear.size();
+ if(closest_index != -1)
+ return closest_index;
+ return num_vertices;
}
// TODO: Optimize text editing by only processing the changed parts in updateGeometry.
@@ -577,18 +595,18 @@ namespace QuickMedia
{
if(!editable) return;
- bool caretAtEnd = textElements.size() == 0 || textElements[0].text.size == 0 || caretIndex == (int)textElements[0].text.size;
+ bool caretAtEnd = caretIndex == (int)vertices_linear.size();
if(event.type == sf::Event::KeyPressed)
{
if(event.key.code == sf::Keyboard::Left && caretIndex > 0)
{
- --caretIndex;
+ caretMoveDirection = CaretMoveDirection::LEFT;
dirtyCaret = true;
}
else if(event.key.code == sf::Keyboard::Right && !caretAtEnd)
{
- ++caretIndex;
+ caretMoveDirection = CaretMoveDirection::RIGHT;
dirtyCaret = true;
}
else if(event.key.code == sf::Keyboard::BackSpace && caretIndex > 0)
@@ -621,7 +639,7 @@ namespace QuickMedia
{
caretMoveDirection = CaretMoveDirection::END;
}
- else if(event.key.code == sf::Keyboard::Return)
+ else if(event.key.code == sf::Keyboard::Enter)
{
if(event.key.shift)
{