mirror of
https://github.com/mudita/MuditaOS.git
synced 2026-01-24 22:08:33 -05:00
* EGD-3407 gui::Text addded TextFormat class - to store format * EGD-3407 Added gray text to Icon text in sms
196 lines
5.2 KiB
C++
196 lines
5.2 KiB
C++
#include "TextBlockCursor.hpp"
|
|
#include "TextBlock.hpp"
|
|
#include "TextDocument.hpp"
|
|
#include "TextParse.hpp"
|
|
#include "log/log.hpp"
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <iterator>
|
|
|
|
static const int last_char_inclusive = 0; // if then -1 / else 0
|
|
|
|
#define debug_cursor(...)
|
|
// #define debug_cursor(...) LOG_DEBUG(__VA_ARGS__)
|
|
|
|
namespace gui
|
|
{
|
|
auto BlockCursor::curentBlock()
|
|
{
|
|
if (block_nr == text::npos) {
|
|
return std::end(document->blocks);
|
|
}
|
|
return std::next(document->blocks.begin(), block_nr);
|
|
}
|
|
|
|
auto BlockCursor::blocksEnd()
|
|
{
|
|
return std::end(document->blocks);
|
|
}
|
|
|
|
BlockCursor::BlockCursor(TextDocument *document, unsigned int pos, unsigned int block_nr, Font *default_font)
|
|
: document(document), default_font(default_font)
|
|
{
|
|
this->pos = text::npos;
|
|
this->block_nr = text::npos;
|
|
if (checkDocument()) {
|
|
this->block_nr = block_nr < document->blocks.size() ? block_nr : document->blocks.size() - 1;
|
|
auto block_len = std::next(document->blocks.begin(), this->block_nr)->length();
|
|
this->pos = pos < block_len ? pos : block_len + last_char_inclusive;
|
|
}
|
|
}
|
|
|
|
[[nodiscard]] auto BlockCursor::checkNpos() const -> bool
|
|
{
|
|
return pos == text::npos || block_nr == text::npos;
|
|
}
|
|
|
|
void BlockCursor::resetNpos()
|
|
{
|
|
if (pos == text::npos)
|
|
pos = 0;
|
|
if (block_nr == text::npos)
|
|
block_nr = 0;
|
|
}
|
|
|
|
[[nodiscard]] auto BlockCursor::checkDocument() const -> bool
|
|
{
|
|
return document != nullptr && document->blocks.size() > 0;
|
|
}
|
|
|
|
auto BlockCursor::atEnd() const -> bool
|
|
{
|
|
if (!checkDocument() || checkNpos()) {
|
|
return false;
|
|
}
|
|
return block_nr == document->blocks.size() - 1 && pos == document->blocks.back().length() + last_char_inclusive;
|
|
}
|
|
|
|
auto BlockCursor::operator+=(unsigned int val) -> BlockCursor &
|
|
{
|
|
// just use operator ++
|
|
for (unsigned int i = 0; i < val; ++i, ++*this) {}
|
|
return *this;
|
|
}
|
|
|
|
BlockCursor &BlockCursor::operator++()
|
|
{
|
|
if (!checkDocument()) {
|
|
return *this;
|
|
}
|
|
else {
|
|
}
|
|
|
|
resetNpos();
|
|
|
|
bool end_of_current_block_reached =
|
|
pos >= std::next(document->blocks.begin(), block_nr)->length() + last_char_inclusive;
|
|
bool last_document_reached = block_nr + 1 == document->blocks.size();
|
|
|
|
if (end_of_current_block_reached && last_document_reached) {
|
|
return *this;
|
|
}
|
|
|
|
if (end_of_current_block_reached) {
|
|
block_nr += 1;
|
|
pos = 0;
|
|
return *this;
|
|
}
|
|
|
|
pos += 1;
|
|
return *this;
|
|
}
|
|
|
|
auto BlockCursor::operator-=(unsigned int val) -> BlockCursor &
|
|
{
|
|
// just use operator --
|
|
for (unsigned int i = 0; i < val; ++i, --*this) {}
|
|
return *this;
|
|
}
|
|
|
|
BlockCursor &BlockCursor::operator--()
|
|
{
|
|
if (!checkDocument()) {
|
|
return *this;
|
|
}
|
|
|
|
resetNpos();
|
|
|
|
if (pos == 0 && block_nr == 0) {
|
|
return *this;
|
|
}
|
|
|
|
if (pos == 0) {
|
|
block_nr -= 1;
|
|
pos = std::next(document->blocks.begin(), block_nr)->length() + last_char_inclusive;
|
|
return *this;
|
|
}
|
|
|
|
pos -= 1;
|
|
return *this;
|
|
}
|
|
|
|
void BlockCursor::addChar(uint32_t utf_val)
|
|
{
|
|
if (document->blocks.size() == 0) {
|
|
if (utf_val == text::newline) {
|
|
document->append(TextBlock("", default_font, TextBlock::End::Newline));
|
|
block_nr = 0;
|
|
pos = 0;
|
|
return;
|
|
}
|
|
document->append(TextBlock("", default_font, TextBlock::End::None));
|
|
block_nr = 0;
|
|
pos = 0;
|
|
}
|
|
auto block = curentBlock();
|
|
if (block == blocksEnd()) {
|
|
LOG_ERROR("add char to document with no text blocks shouldn't ever happen");
|
|
return;
|
|
}
|
|
if (utf_val == text::newline) {
|
|
document->addNewline(*this, TextBlock::End::Newline);
|
|
return;
|
|
}
|
|
block->addChar(utf_val, pos);
|
|
}
|
|
|
|
void BlockCursor::addTextBlock(TextBlock &&textblock)
|
|
{
|
|
if (textblock.length() == 0) {
|
|
return;
|
|
}
|
|
if (document->isEmpty()) {
|
|
block_nr = 0;
|
|
pos = 0;
|
|
}
|
|
document->append(std::move(textblock));
|
|
}
|
|
|
|
bool BlockCursor::removeChar()
|
|
{
|
|
if (checkNpos()) {
|
|
LOG_ERROR("cant remove from not initialized/empty cursor");
|
|
return false;
|
|
}
|
|
|
|
auto block = curentBlock();
|
|
if (block == blocksEnd()) {
|
|
LOG_ERROR("removing char from document with no TextBlocks");
|
|
return false;
|
|
}
|
|
|
|
debug_cursor("From block: [%d], remove pos: [%d] block length [%d]", getBlockNr(), pos, block->length());
|
|
block->removeChar(pos);
|
|
if (block->isEmpty()) {
|
|
debug_cursor("empty block removed");
|
|
document->removeBlock(block);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
const TextBlock &BlockCursor::operator*()
|
|
{
|
|
return *curentBlock();
|
|
}
|
|
} // namespace gui
|