mirror of
https://github.com/mudita/MuditaOS.git
synced 2026-01-24 22:08:33 -05:00
262 lines
9.4 KiB
C++
262 lines
9.4 KiB
C++
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
|
|
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
|
|
|
#include "TextLineCursor.hpp"
|
|
#include "Text.hpp"
|
|
#include "log/log.hpp"
|
|
|
|
#define debug_text_cursor(...)
|
|
// #define debug_text_cursor(...) LOG_DEBUG(__VA_ARGS__)
|
|
|
|
namespace gui
|
|
{
|
|
TextLineCursor::TextLineCursor(gui::Text *parent, unsigned int pos, unsigned int block)
|
|
: TextCursor(parent, pos, block)
|
|
{}
|
|
|
|
auto TextLineCursor::checkNextLineDocumentEnd(unsigned int selectedLineNumber) -> bool
|
|
{
|
|
auto nextLine = text->lines->getLine(selectedLineNumber + 1);
|
|
auto selectedLine = text->lines->getLine(selectedLineNumber);
|
|
|
|
return nextLine->length() == 0 && selectedLine->getEnd() != TextBlock::End::Newline;
|
|
}
|
|
|
|
void TextLineCursor::handleDownNavigation(unsigned int selectedLineNumber, unsigned int selectedLineCursorPosition)
|
|
{
|
|
auto selectedLine = text->lines->getLine(selectedLineNumber);
|
|
auto nextLine = text->lines->getLine(selectedLineNumber + 1);
|
|
auto nextLineEndAddition = nextLine->getEnd() == TextBlock::End::Newline ? 1 : 0;
|
|
|
|
auto noNewAtBeginningAddition =
|
|
selectedLine->getEnd() == TextBlock::End::None && selectedLineCursorPosition == 0 ? 1 : 0;
|
|
|
|
auto nextLineMoveCount = nextLine->length() > selectedLineCursorPosition
|
|
? selectedLineCursorPosition
|
|
: nextLine->length() - nextLineEndAddition;
|
|
|
|
// Next line will be displayed as part of Right move action on right lines border
|
|
auto moveCount =
|
|
(selectedLine->length() - selectedLineCursorPosition) + nextLineMoveCount + noNewAtBeginningAddition;
|
|
|
|
moveCursor(NavigationDirection::RIGHT, moveCount);
|
|
}
|
|
|
|
void TextLineCursor::handleUpNavigation(unsigned int selectedLineNumber, unsigned int selectedLineCursorPosition)
|
|
{
|
|
auto previousLine = text->lines->getLine(selectedLineNumber - 1);
|
|
auto previousLineEndAddition = previousLine->getEnd() == TextBlock::End::Newline ? 1 : 0;
|
|
|
|
auto previousLineMoveCount = previousLine->length() > selectedLineCursorPosition
|
|
? previousLine->length() - previousLineEndAddition - selectedLineCursorPosition
|
|
: 0;
|
|
|
|
auto newLineAtBeginningSubtraction =
|
|
previousLine->getEnd() == TextBlock::End::Newline && selectedLineCursorPosition == 0 ? 1 : 0;
|
|
|
|
auto moveCount = selectedLineCursorPosition + previousLineEndAddition + previousLineMoveCount -
|
|
newLineAtBeginningSubtraction;
|
|
|
|
moveCursor(NavigationDirection::LEFT, moveCount);
|
|
}
|
|
|
|
auto TextLineCursor::displayPreviousLine() -> bool
|
|
{
|
|
if (!text->lines->previousLinesStart.empty()) {
|
|
|
|
auto [lineStartBlockNumber, lineStartBlockPosition] = text->lines->previousLinesStart.back();
|
|
text->lines->previousLinesStart.pop_back();
|
|
text->lines->drawStartConditions = {lineStartBlockNumber, lineStartBlockPosition};
|
|
|
|
text->drawLines();
|
|
|
|
auto moveCount = text->lines->first().length();
|
|
|
|
// update cursor position on screen so it points in same place after scroll
|
|
onScreenPosition += moveCount;
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
auto TextLineCursor::displayNextLine() -> bool
|
|
{
|
|
if (text->lines->stopCondition != LinesDrawStop::OutOfText) {
|
|
|
|
text->lines->addToPreviousLinesStartList(text->lines->first().getLineStartBlockNumber(),
|
|
text->lines->first().getLineStartBlockPosition());
|
|
|
|
auto moveCount = text->lines->first().length();
|
|
|
|
text->lines->drawStartConditions = {text->lines->getLine(1)->getLineStartBlockNumber(),
|
|
text->lines->getLine(1)->getLineStartBlockPosition()};
|
|
|
|
text->drawLines();
|
|
|
|
// update cursor position on screen so it points in same place after scroll
|
|
onScreenPosition -= moveCount;
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
auto TextLineCursor::moveCursor(gui::NavigationDirection direction) -> gui::TextCursor::Move
|
|
{
|
|
debug_text_cursor("Before move cursor: screen pos: %d block: %d pos: %d %s",
|
|
onScreenPosition,
|
|
getBlockNumber(),
|
|
BlockCursor::getPosition(),
|
|
atBegin() ? "at begin" : "middle");
|
|
|
|
if (!checkDocument()) {
|
|
return Move::Error;
|
|
}
|
|
|
|
auto [selectedLine, selectedLineCursorPosition, selectedLineNumber] = getSelectedLine();
|
|
|
|
// last line is sometimes not visible (sometimes empty) and added only for scrolling purposes.
|
|
unsigned int lastVisibleLineNumber = text->lines->countVisible() - 1;
|
|
|
|
debug_text_cursor(
|
|
"Selected line cursor pos: %d, selected line nr: %d", selectedLineCursorPosition, selectedLineNumber);
|
|
|
|
// No lines draw yet to navigate top bottom -> check left/right text navigation
|
|
if (selectedLine == nullptr) {
|
|
return TextCursor::moveCursor(direction);
|
|
}
|
|
|
|
/// up - corner case
|
|
if ((checkNpos() || (direction == NavigationDirection::UP && selectedLineNumber == 0))) {
|
|
|
|
if (!text->lines->previousLinesStart.empty()) {
|
|
|
|
displayPreviousLine();
|
|
|
|
return moveCursor(NavigationDirection::UP);
|
|
}
|
|
else {
|
|
return TextCursor::Move::Start;
|
|
}
|
|
}
|
|
|
|
/// down - corner case
|
|
if ((checkNpos() || (direction == NavigationDirection::DOWN && selectedLineNumber == lastVisibleLineNumber))) {
|
|
|
|
if (text->lines->stopCondition != LinesDrawStop::OutOfText) {
|
|
|
|
if (checkNextLineDocumentEnd(selectedLineNumber)) {
|
|
return TextCursor::Move::End;
|
|
}
|
|
|
|
handleDownNavigation(selectedLineNumber, selectedLineCursorPosition);
|
|
|
|
return TextCursor::Move::Down;
|
|
}
|
|
else {
|
|
return TextCursor::Move::End;
|
|
}
|
|
}
|
|
|
|
/// left - corner case
|
|
if ((checkNpos() || (direction == NavigationDirection::LEFT && selectedLineNumber == 0))) {
|
|
|
|
if (!text->lines->previousLinesStart.empty() &&
|
|
(text->lines->first().getLineStartBlockNumber() == getBlockNumber() &&
|
|
text->lines->first().getLineStartBlockPosition() == BlockCursor::getPosition())) {
|
|
|
|
displayPreviousLine();
|
|
|
|
return TextCursor::moveCursor(NavigationDirection::LEFT);
|
|
}
|
|
else {
|
|
return TextCursor::moveCursor(direction);
|
|
}
|
|
}
|
|
|
|
/// right - corner case
|
|
if ((checkNpos() || (direction == NavigationDirection::RIGHT && selectedLineNumber == lastVisibleLineNumber))) {
|
|
|
|
if (text->lines->stopCondition != LinesDrawStop::OutOfText &&
|
|
(selectedLineCursorPosition ==
|
|
(text->lines->getLine(lastVisibleLineNumber)->length() -
|
|
(text->lines->getLine(lastVisibleLineNumber)->getEnd() == TextBlock::End::Newline ? 1 : 0)))) {
|
|
|
|
if (checkNextLineDocumentEnd(selectedLineNumber)) {
|
|
return TextCursor::Move::End;
|
|
}
|
|
|
|
auto ret = TextCursor::moveCursor(NavigationDirection::RIGHT);
|
|
|
|
displayNextLine();
|
|
|
|
return ret;
|
|
}
|
|
else {
|
|
|
|
return TextCursor::moveCursor(direction);
|
|
}
|
|
}
|
|
|
|
if (direction == NavigationDirection::UP) {
|
|
|
|
handleUpNavigation(selectedLineNumber, selectedLineCursorPosition);
|
|
|
|
debug_text_cursor("After move cursor: screen pos: %d block: %d pos: %d %s",
|
|
onScreenPosition,
|
|
getBlockNumber(),
|
|
BlockCursor::getPosition(),
|
|
atBegin() ? "at begin" : "middle");
|
|
|
|
return Move::Up;
|
|
}
|
|
|
|
if (direction == NavigationDirection::DOWN) {
|
|
|
|
handleDownNavigation(selectedLineNumber, selectedLineCursorPosition);
|
|
|
|
debug_text_cursor("After move cursor: screen pos: %d block: %d pos: %d %s",
|
|
onScreenPosition,
|
|
getBlockNumber(),
|
|
BlockCursor::getPosition(),
|
|
atBegin() ? "at begin" : "middle");
|
|
|
|
return Move::Down;
|
|
}
|
|
|
|
return TextCursor::moveCursor(direction);
|
|
}
|
|
|
|
TextCursor::Move TextLineCursor::moveCursor(NavigationDirection direction, unsigned int n)
|
|
{
|
|
auto ret = TextCursor::Move::Start;
|
|
|
|
for (unsigned int i = 0; i < n; i++) {
|
|
ret = TextLineCursor::moveCursor(direction);
|
|
|
|
if (ret == Move::Start || ret == Move::End || ret == Move::Error) {
|
|
break;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool TextLineCursor::removeChar()
|
|
{
|
|
auto linesSize = text->lines->size();
|
|
|
|
auto ret = TextCursor::removeChar();
|
|
|
|
// After sign removal check if lines count decreased - if so add previous line,
|
|
if (ret && linesSize > text->lines->size()) {
|
|
displayPreviousLine();
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
} // namespace gui
|