mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-28 01:59:59 +01:00
[escher] TextArea can now edit its content
Change-Id: I129a184bc94975c8dd5fd2e7b8c63309978bff02
This commit is contained in:
@@ -13,6 +13,7 @@ public:
|
||||
KDColor textColor = KDColorBlack, KDColor backgroundColor = KDColorWhite);
|
||||
|
||||
void setDelegate(TextAreaDelegate * delegate);
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
|
||||
private:
|
||||
class Text {
|
||||
@@ -42,12 +43,12 @@ private:
|
||||
|
||||
class Position {
|
||||
public:
|
||||
Position(size_t column, size_t line) : m_column(column), m_line(line) {}
|
||||
size_t column() const { return m_column; }
|
||||
size_t line() const { return m_line; }
|
||||
Position(int column, int line) : m_column(column), m_line(line) {}
|
||||
int column() const { return m_column; }
|
||||
int line() const { return m_line; }
|
||||
private:
|
||||
size_t m_column;
|
||||
size_t m_line;
|
||||
int m_column;
|
||||
int m_line;
|
||||
};
|
||||
|
||||
LineIterator begin() const { return LineIterator(m_buffer); };
|
||||
@@ -55,12 +56,11 @@ private:
|
||||
|
||||
Position span() const;
|
||||
|
||||
void insert(char c, Position p);
|
||||
void remove(Position p);
|
||||
private:
|
||||
Position positionAtIndex(size_t index);
|
||||
size_t indexAtPosition(Position p);
|
||||
void insert(char c, size_t index);
|
||||
void remove(size_t index);
|
||||
|
||||
void insertChar(char c, size_t index);
|
||||
void removeChar(size_t index);
|
||||
private:
|
||||
char * m_buffer;
|
||||
size_t m_bufferSize;
|
||||
@@ -72,7 +72,18 @@ private:
|
||||
KDColor textColor, KDColor backgroundColor);
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
KDSize minimalSizeForOptimalDisplay() const override;
|
||||
void insertText(const char * text);
|
||||
void moveCursorIndex(int deltaX);
|
||||
void moveCursorGeo(int deltaX, int deltaY);
|
||||
void removeChar();
|
||||
KDRect cursorRect();
|
||||
private:
|
||||
int numberOfSubviews() const override;
|
||||
View * subviewAtIndex(int index) override;
|
||||
void layoutSubviews() override;
|
||||
KDRect characterFrameAtIndex(size_t index);
|
||||
TextCursorView m_cursorView;
|
||||
size_t m_cursorIndex;
|
||||
Text m_text;
|
||||
KDText::FontSize m_fontSize;
|
||||
KDColor m_textColor;
|
||||
|
||||
@@ -5,6 +5,11 @@
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
static inline size_t min(size_t a, size_t b) {
|
||||
return (a>b ? b : a);
|
||||
}
|
||||
|
||||
TextArea::Text::Text(char * buffer, size_t bufferSize) :
|
||||
m_buffer(buffer),
|
||||
m_bufferSize(bufferSize)
|
||||
@@ -35,21 +40,40 @@ TextArea::Text::LineIterator & TextArea::Text::LineIterator::operator++() {
|
||||
}
|
||||
|
||||
size_t TextArea::Text::indexAtPosition(Position p) {
|
||||
if (p.line() < 0) {
|
||||
return 0;
|
||||
}
|
||||
size_t y = 0;
|
||||
const char * endOfLastLine = nullptr;
|
||||
for (Line l : *this) {
|
||||
if (p.line() == y) {
|
||||
size_t x = (p.column() > l.length() ? l.length() : p.column());
|
||||
size_t x = min(p.column(), l.length());
|
||||
return l.text() - m_buffer + x;
|
||||
}
|
||||
endOfLastLine = l.text() + l.length();
|
||||
y++;
|
||||
}
|
||||
assert(endOfLastLine != nullptr && endOfLastLine >= m_buffer);
|
||||
return endOfLastLine - m_buffer;
|
||||
}
|
||||
|
||||
TextArea::Text::Position TextArea::Text::positionAtIndex(size_t index) {
|
||||
assert(index < m_bufferSize);
|
||||
const char * target = m_buffer + index;
|
||||
size_t y = 0;
|
||||
for (Line l : *this) {
|
||||
if (l.text() <= target && l.text() + l.length() >= target) {
|
||||
size_t x = target - l.text();
|
||||
return Position(x, y);
|
||||
}
|
||||
y++;
|
||||
}
|
||||
assert(false);
|
||||
return 0;
|
||||
return Position(0, 0);
|
||||
}
|
||||
|
||||
void TextArea::Text::insert(char c, size_t index) {
|
||||
void TextArea::Text::insertChar(char c, size_t index) {
|
||||
assert(index < m_bufferSize);
|
||||
char * cursor = m_buffer + index;
|
||||
char previous = c;
|
||||
for (size_t i=index; i<m_bufferSize; i++) {
|
||||
char inserted = previous;
|
||||
@@ -61,7 +85,7 @@ void TextArea::Text::insert(char c, size_t index) {
|
||||
}
|
||||
}
|
||||
|
||||
void TextArea::Text::remove(size_t index) {
|
||||
void TextArea::Text::removeChar(size_t index) {
|
||||
assert(index < m_bufferSize);
|
||||
for (size_t i=index; i<m_bufferSize; i++) {
|
||||
m_buffer[i] = m_buffer[i+1];
|
||||
@@ -87,6 +111,7 @@ TextArea::Text::Position TextArea::Text::span() const {
|
||||
|
||||
TextArea::ContentView::ContentView(char * textBuffer, size_t textBufferSize, KDText::FontSize fontSize, KDColor textColor, KDColor backgroundColor) :
|
||||
View(),
|
||||
m_cursorIndex(0),
|
||||
m_text(textBuffer, textBufferSize),
|
||||
m_fontSize(fontSize),
|
||||
m_textColor(textColor),
|
||||
@@ -103,9 +128,6 @@ KDSize TextArea::ContentView::minimalSizeForOptimalDisplay() const {
|
||||
);
|
||||
}
|
||||
|
||||
size_t min(size_t a, size_t b) {
|
||||
return (a>b ? b : a);
|
||||
}
|
||||
|
||||
void TextArea::ContentView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
ctx->fillRect(rect, m_backgroundColor);
|
||||
@@ -142,6 +164,61 @@ void TextArea::ContentView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
}
|
||||
}
|
||||
|
||||
int TextArea::ContentView::numberOfSubviews() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
View * TextArea::ContentView::subviewAtIndex(int index) {
|
||||
return &m_cursorView;
|
||||
}
|
||||
|
||||
void TextArea::ContentView::layoutSubviews() {
|
||||
m_cursorView.setFrame(cursorRect());
|
||||
}
|
||||
|
||||
void TextArea::TextArea::ContentView::insertText(const char * text) {
|
||||
while (*text != 0) {
|
||||
m_text.insertChar(*text++, m_cursorIndex++);
|
||||
}
|
||||
layoutSubviews(); // Reposition the cursor
|
||||
markRectAsDirty(bounds()); // FIXME: Vastly suboptimal
|
||||
}
|
||||
|
||||
void TextArea::TextArea::ContentView::removeChar() {
|
||||
if (m_cursorIndex > 0) {
|
||||
m_text.removeChar(--m_cursorIndex);
|
||||
}
|
||||
layoutSubviews(); // Reposition the cursor
|
||||
markRectAsDirty(bounds()); // FIXME: Vastly suboptimal
|
||||
}
|
||||
|
||||
KDRect TextArea::TextArea::ContentView::cursorRect() {
|
||||
return characterFrameAtIndex(m_cursorIndex);
|
||||
}
|
||||
|
||||
KDRect TextArea::TextArea::ContentView::characterFrameAtIndex(size_t index) {
|
||||
KDSize charSize = KDText::stringSize(" ", m_fontSize);
|
||||
Text::Position p = m_text.positionAtIndex(index);
|
||||
return KDRect(
|
||||
p.column() * charSize.width(),
|
||||
p.line() * charSize.height(),
|
||||
charSize.width(),
|
||||
charSize.height()
|
||||
);
|
||||
}
|
||||
|
||||
void TextArea::TextArea::ContentView::moveCursorGeo(int deltaX, int deltaY) {
|
||||
Text::Position p = m_text.positionAtIndex(m_cursorIndex);
|
||||
m_cursorIndex = m_text.indexAtPosition(Text::Position(p.column() + deltaX, p.line() + deltaY));
|
||||
layoutSubviews();
|
||||
}
|
||||
|
||||
void TextArea::TextArea::ContentView::moveCursorIndex(int deltaX) {
|
||||
// FIXME: bound checks!
|
||||
m_cursorIndex += deltaX;
|
||||
layoutSubviews();
|
||||
}
|
||||
|
||||
/* TextArea */
|
||||
|
||||
TextArea::TextArea(Responder * parentResponder, char * textBuffer,
|
||||
@@ -153,6 +230,26 @@ TextArea::TextArea(Responder * parentResponder, char * textBuffer,
|
||||
{
|
||||
}
|
||||
|
||||
bool TextArea::TextArea::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Left) {
|
||||
m_contentView.moveCursorIndex(-1);
|
||||
} else if (event == Ion::Events::Right) {
|
||||
m_contentView.moveCursorIndex(1);
|
||||
} else if (event == Ion::Events::Up) {
|
||||
m_contentView.moveCursorGeo(0, -1);
|
||||
} else if (event == Ion::Events::Down) {
|
||||
m_contentView.moveCursorGeo(0, 1);
|
||||
} else if (event == Ion::Events::Backspace) {
|
||||
m_contentView.removeChar();
|
||||
} else if (event.hasText()) {
|
||||
m_contentView.insertText(event.text());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
scrollToContentRect(m_contentView.cursorRect());
|
||||
return true;
|
||||
}
|
||||
|
||||
View * TextArea::view() {
|
||||
return &m_contentView;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user