10 static inline size_t min(
size_t a,
size_t b) {
14 TextArea::Text::Text(
char * buffer,
size_t bufferSize) :
16 m_bufferSize(bufferSize)
20 void TextArea::Text::setText(
char * buffer,
size_t bufferSize) {
22 m_bufferSize = bufferSize;
29 if (m_text !=
nullptr) {
30 while (*
text != 0 && *
text !=
'\n') {
33 m_length =
text-m_text;
38 return (
c >= m_text) && (
c < m_text + m_length);
42 const char * last = m_line.text() + m_line.length();
43 m_line =
Line(*last == 0 ?
nullptr : last+1);
47 size_t TextArea::Text::indexAtPosition(
Position p) {
48 assert(m_buffer !=
nullptr);
53 const char * endOfLastLine =
nullptr;
54 for (Line l : *
this) {
57 x = min(x, l.length());
58 return l.text() - m_buffer + x;
60 endOfLastLine = l.text() + l.length();
63 assert(endOfLastLine !=
nullptr && endOfLastLine >= m_buffer);
64 return endOfLastLine - m_buffer;
68 assert(m_buffer !=
nullptr);
69 assert(index < m_bufferSize);
70 const char * target = m_buffer + index;
72 for (Line l : *
this) {
73 if (l.text() <= target && l.text() + l.length() >= target) {
74 size_t x = target - l.text();
75 return Position(x, y);
80 return Position(0, 0);
83 void TextArea::Text::insertChar(
char c,
size_t index) {
84 assert(m_buffer !=
nullptr);
85 assert(index < m_bufferSize-1);
87 for (
size_t i=index; i<m_bufferSize; i++) {
88 char inserted = previous;
89 previous = m_buffer[i];
90 m_buffer[i] = inserted;
97 char TextArea::Text::removeChar(
size_t index) {
98 assert(m_buffer !=
nullptr);
99 assert(index < m_bufferSize-1);
100 char deletedChar = m_buffer[index];
101 for (
size_t i=index; i<m_bufferSize; i++) {
102 m_buffer[i] = m_buffer[i+1];
103 if (m_buffer[i] == 0) {
110 int TextArea::Text::removeRemainingLine(
size_t index,
int direction) {
111 assert(m_buffer !=
nullptr);
112 assert(index < m_bufferSize);
114 while (m_buffer[jump] !=
'\n' && m_buffer[jump] != 0 && jump >= 0) {
117 int delta = direction > 0 ? jump - index : index - jump;
124 for (
size_t k = index; k < m_bufferSize-1; k++) {
126 m_buffer[k] = m_buffer[jump++];
128 m_buffer[++jump] = m_buffer[k+1];
130 if (m_buffer[k] == 0 || m_buffer[k+1] == 0) {
139 assert(m_buffer !=
nullptr);
142 for (Line l : *
this) {
143 if (l.length() > width) {
148 return Position(width, height);
155 m_text(textBuffer, textBufferSize)
159 KDSize TextArea::ContentView::minimalSizeForOptimalDisplay()
const {
161 Text::Position span = m_text.span();
165 charSize.
width() * (span.column()+1),
166 charSize.
height() * span.line()
171 void TextArea::ContentView::drawRect(
KDContext * ctx,
KDRect rect)
const {
172 ctx->
fillRect(rect, m_backgroundColor);
178 Text::Position topLeft(
179 rect.
x()/charSize.
width(),
182 Text::Position bottomRight(
188 size_t x = topLeft.column();
190 for (Text::Line line : m_text) {
191 if (y >= topLeft.line() && y <= bottomRight.line() && topLeft.column() < (int)line.length()) {
194 line.text() + topLeft.column(),
199 min(line.length() - topLeft.column(), bottomRight.column() - topLeft.column())
206 void TextArea::TextArea::ContentView::setText(
char * textBuffer,
size_t textBufferSize) {
207 m_text.setText(textBuffer, textBufferSize);
211 const char * TextArea::TextArea::ContentView::text()
const {
212 return m_text.text();
215 bool TextArea::TextArea::ContentView::insertTextAtLocation(
const char *
text,
int location) {
217 if (m_text.textLength() + textSize >= m_text.bufferSize() || textSize == 0) {
220 bool lineBreak =
false;
221 int currentLocation = location;
223 lineBreak |= *
text ==
'\n';
224 m_text.insertChar(*
text++, currentLocation++);
226 reloadRectFromCursorPosition(currentLocation-1, lineBreak);
230 bool TextArea::TextArea::ContentView::removeChar() {
234 bool lineBreak =
false;
235 assert(m_cursorIndex > 0);
236 lineBreak = m_text.removeChar(--m_cursorIndex) ==
'\n';
242 bool TextArea::ContentView::removeEndOfLine() {
243 int removedLine = m_text.removeRemainingLine(
cursorLocation(), 1);
244 if (removedLine > 0) {
252 bool TextArea::ContentView::removeStartOfLine() {
256 int removedLine = m_text.removeRemainingLine(
cursorLocation()-1, -1);
257 if (removedLine > 0) {
258 assert(m_cursorIndex >= removedLine);
266 KDRect TextArea::TextArea::ContentView::characterFrameAtIndex(
size_t index)
const {
268 Text::Position p = m_text.positionAtIndex(index);
270 p.column() * charSize.
width(),
271 p.line() * charSize.
height(),
277 void TextArea::TextArea::ContentView::moveCursorGeo(
int deltaX,
int deltaY) {
278 Text::Position p = m_text.positionAtIndex(m_cursorIndex);
279 setCursorLocation(m_text.indexAtPosition(Text::Position(p.column() + deltaX, p.line() + deltaY)));
288 m_contentView(textBuffer, textBufferSize, fontSize, textColor,
backgroundColor),
314 m_contentView.moveCursorGeo(0, -1);
316 m_contentView.moveCursorGeo(0, 1);
318 m_contentView.moveCursorGeo(-
INT_MAX/2, 0);
320 m_contentView.moveCursorGeo(
INT_MAX/2, 0);
328 if (!m_contentView.removeEndOfLine()) {
329 m_contentView.removeStartOfLine();
341 m_contentView.setText(textBuffer, textBufferSize);
342 m_contentView.moveCursorGeo(0, 0);
345 bool TextArea::insertTextWithIndentation(
const char * textBuffer,
int location) {
346 int indentation = indentationBeforeCursor();
347 char spaceString[indentation+1];
348 for (
int i = 0; i < indentation; i++) {
349 spaceString[i] =
' ';
351 spaceString[indentation] = 0;
352 int spaceStringSize =
strlen(spaceString);
353 int textSize =
strlen(textBuffer);
354 int totalIndentationSize = 0;
355 for (
size_t i = 0; i <
strlen(textBuffer); i++) {
356 if (textBuffer[i] ==
'\n') {
357 totalIndentationSize+=spaceStringSize;
360 if (m_contentView.getText()->textLength() + textSize + totalIndentationSize >= m_contentView.getText()->bufferSize() || textSize == 0) {
363 int currentLocation = location;
364 for (
size_t i = 0; i <
strlen(textBuffer); i++) {
365 const char charString[] = {textBuffer[i], 0};
367 if (textBuffer[i] ==
'\n') {
369 currentLocation +=
strlen(spaceString);
375 int TextArea::indentationBeforeCursor()
const {
377 int indentationSize = 0;
378 while (charIndex >= 0 && m_contentView.text()[charIndex] !=
'\n') {
379 if (m_contentView.text()[charIndex] ==
' ') {
386 return indentationSize;
bool setCursorLocation(int location)
bool contains(const char *c) const
KDPoint drawString(const char *text, KDPoint p, KDText::FontSize size=KDText::FontSize::Large, KDColor textColor=KDColorBlack, KDColor backgroundColor=KDColorWhite, int maxLength=-1)
size_t cursorLocation() const
constexpr KDCoordinate width() const
Responder * parentResponder() const
virtual bool handleEvent(Ion::Events::Event event)
KDCoordinate right() const
virtual void scrollToCursor()
size_t strlen(const char *s)
bool insertTextAtLocation(const char *textBuffer, int location)
const char * text() const
LineIterator & operator++()
bool handleEvent(Ion::Events::Event event) override
const char * text() const
const char * text() const
constexpr Event ShiftLeft
void setText(char *textBuffer, size_t textBufferSize)
void fillRect(KDRect rect, KDColor color)
virtual bool textAreaDidReceiveEvent(TextArea *textArea, Ion::Events::Event event)=0
constexpr Event ShiftRight
static Clipboard * sharedClipboard()
static constexpr KDSize charSize(FontSize size=FontSize::Large)
KDColor backgroundColor() const
ContentView(KDText::FontSize size, KDColor textColor, KDColor backgroundColor)
int CursorIndexInCommand(const char *text)
bool handleEventWithText(const char *text, bool indentation=false) override
KDCoordinate bottom() const
constexpr Event Backspace
constexpr KDCoordinate height() const
TextArea(Responder *parentResponder, char *textBuffer=nullptr, size_t textBufferSize=0, TextAreaDelegate *delegate=nullptr, KDText::FontSize fontSize=KDText::FontSize::Large, KDColor textColor=KDColorBlack, KDColor backgroundColor=KDColorWhite)