#include "TextFeld.h" #include #include "AlphaFeld.h" #include "Bild.h" #include "Fenster.h" #include "Globals.h" #include "MausEreignis.h" #include "Rahmen.h" #include "Schrift.h" #include "Scroll.h" #include "TastaturEreignis.h" #include "Text.h" #include "ToolTip.h" using namespace Framework; #ifndef test # define test bool TextStyle::equals(const TextStyle& rhs) { return fontSize == rhs.fontSize && fontColor == rhs.fontColor && selectedColor == rhs.selectedColor && selectedBackcroundColor == rhs.selectedBackcroundColor && underlined == rhs.underlined && selected == rhs.selected && interactParam == rhs.interactParam && rendererIndex == rhs.rendererIndex; } #endif TextFeld::TextStyleManager::TextStyleManager() : ReferenceCounter(), renderer(new RCArray()), index(0), styleIndex(0), text(0) { current.beginIndex = 0; current.fontColor = 0xFFFFFFFF; current.fontSize = 12; current.selected = 0; current.selectedColor = 0xFFFFFFFF; current.selectedBackcroundColor = 0xFF0000FF; current.underlined = 0; current.interactParam = 0; current.rendererIndex = 0; textStyle.add(current); } TextFeld::TextStyleManager::~TextStyleManager() { if (renderer) renderer->release(); if (text) text->release(); } // Setzt den Style eines Textabschnittes // begin: die startposition des Abschnittes // end: die endposition des Abschnittes (nicht enthalten) void TextFeld::TextStyleManager::setTextStyle( int begin, int end, TextStyle style) { if (begin < 0 || begin > end || begin > text->getLength()) return; int sc = textStyle.getEintragAnzahl(); int index = -1; TextStyle s = textStyle.get(0); // suche bis zur richtigen stelle im stylearray for (int i = 0; i < sc; i++) { if (textStyle.get(i).beginIndex >= begin) { index = i; if (textStyle.get(i).beginIndex > begin) s = textStyle.get(i - 1); else { s = textStyle.get(i); textStyle.remove(i); sc--; } break; } } style.beginIndex = begin; s.beginIndex = end; if (index < 0) { // hinten an styles anfügen textStyle.add(style); textStyle.add(s); } else { // in die mitte des style arrays einfügen textStyle.add(style, index); for (int i = index + 1; i < sc + 1; i++) { // styles entfernen die überschrieben wurden if (textStyle.get(i).beginIndex <= end && textStyle.get(i).beginIndex > begin) { s = textStyle.get(i); textStyle.remove(i); i--; sc--; } } s.beginIndex = end; textStyle.add(s, index + 1); } cleanupStyles(); } // Entfernt einen Textabschnitt // begin: der index des ersten betroffenen zeichens // end: der index des ersten zeichens nach dem abschnitt void TextFeld::TextStyleManager::removeText(int begin, int end) { int sc = textStyle.getEintragAnzahl(); for (int i = 1; i < sc; i++) { TextStyle s = textStyle.get(i); if (s.beginIndex >= begin && s.beginIndex < end) { textStyle.remove(i); i--; sc--; } if (s.beginIndex >= end) { s.beginIndex -= end - begin; textStyle.set(s, i); } } text->remove(begin, end); cleanupStyles(); } // Fügt ein Text an einer bestimmten Position ein // pos: die position des neuen Textausschnitts // text: der neue Text void TextFeld::TextStyleManager::insertText(int pos, const char* text) { int len = textLength(text); this->text->insert(pos, text); int sc = textStyle.getEintragAnzahl(); for (int i = 0; i < sc; i++) { TextStyle s = textStyle.get(i); if (s.beginIndex > pos) { s.beginIndex += len; textStyle.set(s, i); } } cleanupStyles(); } // Entfernt nicht benötiegte gleiche styles void TextFeld::TextStyleManager::cleanupStyles() { int sc = textStyle.getEintragAnzahl(); TextStyle last = textStyle.get(0); for (int i = 1; i < sc; i++) { if (textStyle.get(i).beginIndex == last.beginIndex) { last = textStyle.get(i); textStyle.remove(i - 1); i--; sc--; continue; } if (textStyle.get(i).equals(last) || (text && textStyle.get(i).beginIndex > text->getLength())) { textStyle.remove(i); i--; sc--; } else last = textStyle.get(i); } } // gibt eine referenz auf das style objekt zurück TextStyle& TextFeld::TextStyleManager::currentStyle() { return current; } // gibt den aktuellen text renderer zurück TextRenderer* TextFeld::TextStyleManager::zCurrentRenderer() { if (renderer->getEintragAnzahl() == 0) return 0; TextRenderer* tr = renderer->z(current.rendererIndex); if (!tr) tr = renderer->z(0); if (tr) tr->setSchriftSize(current.fontSize); return tr; } // ändert den inhalt des style objektes auf den style des nächsten zeichens bool TextFeld::TextStyleManager::nextStyle() { index++; if (textStyle.getEintragAnzahl() > styleIndex + 1 && index >= textStyle.get(styleIndex + 1).beginIndex) current = textStyle.get(styleIndex++ + 1); return text && index < text->getLength(); } // ändert den inhalt des style objektes auf den style des angegebenen zeichens // index: der Index des Zeichens zu dem gesprungen werden soll // gibt 0 zurück falls es das zeichen nicht gibt bool TextFeld::TextStyleManager::stepTo(int index) { resetIteration(); while (this->index < index && nextStyle()) ; return text && this->index == index; } // ändert den inhalt des style objektes auf den style des ersten zeichens void TextFeld::TextStyleManager::resetIteration() { index = 0; styleIndex = 0; current = textStyle.get(0); } // Gibt den Style eines bestimmten zeichens zurück // index: Der index des Zeichensf TextStyle TextFeld::TextStyleManager::getTextStyle(int index) const { TextStyle last = textStyle.get(0); int ind = 0; for (auto i = textStyle.begin(); i && ind <= index; ind++) { if (i._.beginIndex <= ind) { last = i; i++; } } return last; } // Inhalt der TextFeld Klasse aus TextFeld.h // Konstruktor TextFeld::TextFeld() : ZeichnungHintergrund(), tm(new TextStyleManager()), autoLineBreakSpacing(0), showChar(0), cpos(0), tickVal(0), mausKlick(0) { charEvent = 0; horizontalScrollBar = new HScrollBar(); vertikalScrollBar = new VScrollBar(); this->setMausEreignis(_ret1ME); this->setTastaturEreignis(_ret1TE); } // Destruktor TextFeld::~TextFeld() { tm->release(); if (autoLineBreakSpacing) autoLineBreakSpacing->release(); } void TextFeld::doMausEreignis(MausEreignis& me, bool userRet) // Maus Ereignis { if (!userRet) return; if (hatStyleNicht(Style::Editierbar)) { int rbr = 0; if (rahmen) rbr = rahmen->getRBreite(); if (((vertikalScrollBar && hatStyle(Style::VScroll)) || (horizontalScrollBar && hatStyle(Style::HScroll))) && me.mx > rbr && me.mx < gr.x - rbr && me.my > rbr && me.my < gr.y - rbr) { me.verarbeitet |= vertikalScrollBar->doMausMessage( gr.x - rbr - 15, rbr, 15, gr.y - rbr * 2, me); me.verarbeitet |= horizontalScrollBar->doMausMessage(rbr, gr.y - rbr * 2 - 15, gr.x - rbr * 2 - ((vertikalScrollBar && hatStyle(Style::VScroll)) ? 15 : 0), 15, me); } if (me.mx >= 0 && me.mx <= gr.x && me.my >= 0 && me.my <= gr.y && !me.verarbeitet && hatStyle(Style::Sichtbar)) { int scrollHi = (vertikalScrollBar && hatStyle(Style::VScroll)) ? vertikalScrollBar->getScroll() : 0; int scrollBr = (horizontalScrollBar && hatStyle(Style::HScroll)) ? horizontalScrollBar->getScroll() : 0; int xxx = me.mx - rbr + scrollBr; int yyy = me.my - rbr + scrollHi; int mausChar = getTextIndexAt(xxx, yyy); if (mausChar >= 0) { TextStyle s = tm->getTextStyle(mausChar); if (charEvent && s.interactParam) charEvent(mausChar, s.interactParam, me); } if (charEvent) me.verarbeitet = 1; } mausKlick = 0; return; } if (!me.verarbeitet) { if (hatStyleNicht(Style::Fokus)) { mausKlick = 0; if (me.id == Framework::ME_PLinks) addStyle(Style::Fokus); } int rbr = 0; if (rahmen) rbr = rahmen->getRBreite(); if (vertikalScrollBar && hatStyle(Style::VScroll)) { if (vertikalScrollBar->doMausMessage( gr.x - rbr - 15, rbr, 15, gr.y - rbr * 2, me)) { me.verarbeitet = 1; return; } } if (horizontalScrollBar && hatStyle(Style::HScroll)) { if (horizontalScrollBar->doMausMessage(rbr, gr.y - rbr - 15, gr.x - rbr * 2 - ((vertikalScrollBar && hatStyle(Style::VScroll)) ? 15 : 0), 15, me)) { me.verarbeitet = 1; return; } } bool shift = getTastenStand(T_Shift); bool strg = getTastenStand(T_Strg); int tbr = getTextWidth(); int thi = getTextHeight(); int scrollHi = (vertikalScrollBar && hatStyle(Style::VScroll)) ? vertikalScrollBar->getScroll() : 0; int scrollBr = (horizontalScrollBar && hatStyle(Style::HScroll)) ? horizontalScrollBar->getScroll() : 0; int xxx = me.mx - rbr + scrollBr; int yyy = me.my - rbr + scrollHi; int mausChar = getTextIndexAt(xxx, yyy); int scrollBreite = (vertikalScrollBar && hatStyle(Style::VScroll)) * 15; int scrollHeight = (horizontalScrollBar && hatStyle(Style::HScroll)) * 15; if (hatStyle(Style::HCenter)) xxx -= (((gr.x - scrollBreite) / 2) - tbr / 2) - rbr; if (hatStyle(Style::VCenter) && hatStyleNicht(Style::VScroll)) yyy -= (((gr.y - scrollHeight) / 2) - thi / 2) - rbr; if (mausChar >= 0) { TextStyle s = tm->getTextStyle(mausChar); if (charEvent) charEvent(mausChar, s.interactParam, me); } if (me.mx < gr.x - rbr - 15) { if (tm->renderer) { int ncpos = getCurserPosAt(xxx, yyy); if (me.id == Framework::ME_PLinks) { if (ncpos != -1) { if (shift && cpos != ncpos) addAuswahl(MIN(cpos, ncpos), MAX(cpos, ncpos)); else if (!shift && !mausKlick && !strg) deselectAuswahl(); cpos = ncpos; rend = 1; if (vertikalScrollBar && hatStyle(Style::VScroll)) updateVScroll(); if (horizontalScrollBar && hatStyle(Style::HScroll)) updateHScroll(); } mausKlick = 1; } if (me.id == ME_Bewegung && mausKlick) { if (ncpos != -1) { rend = 1; if (cpos != ncpos) invertAuswahl(MIN(cpos, ncpos), MAX(cpos, ncpos)); cpos = ncpos; if (vertikalScrollBar && hatStyle(Style::VScroll)) updateVScroll(cpos); if (horizontalScrollBar && hatStyle(Style::HScroll)) updateHScroll(cpos); } } if (me.id == ME_RLinks) { if (ncpos != -1) { rend = 1; if (cpos != ncpos) invertAuswahl(MIN(cpos, ncpos), MAX(cpos, ncpos)); cpos = ncpos; if (vertikalScrollBar && hatStyle(Style::VScroll)) updateVScroll(cpos); if (horizontalScrollBar && hatStyle(Style::HScroll)) updateHScroll(cpos); } mausKlick = 0; } } } } me.verarbeitet = 1; } int TextFeld::getTextHeight() const { if (!tm || !tm->text) return 0; tm->resetIteration(); int th = 0; int len = tm->text->getLength(); const char* text = tm->text->getText(); Text txtWithLineBreaks; if (hatStyle(Style::AutoLineBreak)) { txtWithLineBreaks = addLineBreaksToText(tm->text->getText(), autoLineBreakSpacing ? autoLineBreakSpacing->getText() : ""); text = txtWithLineBreaks; len = txtWithLineBreaks.getLength(); } int max = 0; int abstand = 0; for (int i = 0; i < len; i++) { if (text[i] == '\n') { th += max + abstand; abstand = 0; max = 0; tm->nextStyle(); continue; } TextRenderer* r = tm->zCurrentRenderer(); if (r) { int tmp = r->getZeilenHeight(); max = max >= tmp ? max : tmp; if (max == tmp) abstand = r->getZeilenAbstand(); } tm->nextStyle(); } if (max > 0) th += max; return th; } int TextFeld::getTextWidth() const { if (!tm || !tm->text) return 0; tm->resetIteration(); int maxBr = 0; int len = tm->text->getLength(); const char* text = tm->text->getText(); Text txtWithLineBreaks; if (hatStyle(Style::AutoLineBreak)) { txtWithLineBreaks = addLineBreaksToText(tm->text->getText(), autoLineBreakSpacing ? autoLineBreakSpacing->getText() : ""); text = txtWithLineBreaks; len = txtWithLineBreaks.getLength(); } int lineBr = 0; char buff[] = {0, 0}; for (int i = 0; i < len; i++) { buff[0] = text[i]; if (text[i] == '\n') { maxBr = maxBr >= lineBr ? maxBr : lineBr; lineBr = 0; tm->nextStyle(); continue; } TextRenderer* r = tm->zCurrentRenderer(); if (r) lineBr += r->getTextBreite(buff); tm->nextStyle(); } if (lineBr > 0) maxBr = maxBr >= lineBr ? maxBr : lineBr; return maxBr; } // charEvent: eine funktion die aufgerufen wird, wenn sich die maus auf einem // bestimmten zeichen befindet und der interactParam im style != 0 ist // aufruf: charEvent( charIndex, interactParam, mausEreignis ); void TextFeld::setCharEvent( std::function charEvent) { this->charEvent = charEvent; } void TextFeld::setText(Text* txt) // setzt den angezeigten Text { lockZeichnung(); if (!tm->text) tm->text = new Text(); tm->text->setText(txt); if (hatStyle(Style::VScroll)) updateVScroll(); if (hatStyle(Style::HScroll)) updateHScroll(); unlockZeichnung(); rend = 1; } void TextFeld::setTextZ(Text* txt) // setzt einen Zeiger zum angezeigten Text { lockZeichnung(); if (tm->text) tm->text->release(); tm->text = txt; if (hatStyle(Style::VScroll)) updateVScroll(); if (hatStyle(Style::HScroll)) updateHScroll(); rend = 1; unlockZeichnung(); } void TextFeld::setText(const char* txt) // setzt den angezeigten Text { lockZeichnung(); if (!tm->text) tm->text = new Text(); tm->text->setText(txt); if (hatStyle(Style::VScroll)) updateVScroll(); if (hatStyle(Style::HScroll)) updateHScroll(); rend = 1; unlockZeichnung(); } // setzt den Text mit styles // txt: der Text // format: \x1: aktiviert unterschtrich // \x2\xY: setzt die schriftgröße auf y für den folgenden text // \x3\xA\xR\xG\xB: setzt die schriftfarbe auf ARGB // \x4\xA\xR\xG\xB: setzt die farbe des ausgewählten textes // \x5\xA\xR\xG\xB: setzt die hintergrundfarbe des ausgewählten textes // \x6\xY: setzt text renderer index auf y // \x7: deaktiviert unterschtrich // \x8\xA\xB\xC\xD: set interact param to ABCD void TextFeld::setFormattedText(const char* txt) { lockZeichnung(); if (!tm->text) tm->text = new Text(); tm->textStyle.leeren(); TextStyle current; current.beginIndex = 0; current.fontColor = 0xFFFFFFFF; current.fontSize = 12; current.selected = 0; current.selectedColor = 0xFFFFFFFF; current.selectedBackcroundColor = 0xFF0000FF; current.underlined = 0; current.interactParam = 0; current.rendererIndex = 0; tm->textStyle.add(current); Text result = ""; for (int i = 0; 1; i++) { bool br = 0; current.beginIndex = result.getLength(); switch (txt[i]) { case 0: br = 1; break; case 1: current.underlined = 1; tm->textStyle.add(current); break; case 2: current.fontSize = (unsigned char)txt[++i]; tm->textStyle.add(current); break; case 3: current.fontColor = 0; current.fontColor |= (unsigned char)txt[++i] << 24; current.fontColor |= (unsigned char)txt[++i] << 16; current.fontColor |= (unsigned char)txt[++i] << 8; current.fontColor |= (unsigned char)txt[++i]; tm->textStyle.add(current); break; case 4: current.selectedColor = 0; current.selectedColor |= (unsigned char)txt[++i] << 24; current.selectedColor |= (unsigned char)txt[++i] << 16; current.selectedColor |= (unsigned char)txt[++i] << 8; current.selectedColor |= (unsigned char)txt[++i]; tm->textStyle.add(current); break; case 5: current.selectedBackcroundColor = 0; current.selectedBackcroundColor |= (unsigned char)txt[++i] << 24; current.selectedBackcroundColor |= (unsigned char)txt[++i] << 16; current.selectedBackcroundColor |= (unsigned char)txt[++i] << 8; current.selectedBackcroundColor |= (unsigned char)txt[++i]; tm->textStyle.add(current); break; case 6: current.rendererIndex = (unsigned char)txt[++i]; tm->textStyle.add(current); break; case 7: current.underlined = 0; tm->textStyle.add(current); break; case 8: current.interactParam = 0; current.interactParam |= (unsigned char)txt[++i] << 24; current.interactParam |= (unsigned char)txt[++i] << 16; current.interactParam |= (unsigned char)txt[++i] << 8; current.interactParam |= (unsigned char)txt[++i]; tm->textStyle.add(current); break; default: result.append(txt[i]); } if (br) break; } tm->text->setText(result); tm->cleanupStyles(); if (hatStyle(Style::VScroll)) updateVScroll(); if (hatStyle(Style::HScroll)) updateHScroll(); rend = 1; unlockZeichnung(); } // fügt zeilenumbrüche so ein, dass der text nicht die breite des textfeldes // überschreitet void TextFeld::addLineBreaks(const char* spacing) { if (!tm->text) return; setFormattedText(addLineBreaksToText(tm->text->getText(), spacing)); } Text TextFeld::addLineBreaksToText(const char* txt, const char* spacing) const { int lastPos = -1; int lastPos2 = -1; int x = 0; Text result = ""; int len = (int)strlen(txt); int maxBr = getBreite(); if (hatStyle(Style::VScroll) && vertikalScrollBar) maxBr -= 15; tm->resetIteration(); TextStyle last; last.beginIndex = 0; last.fontColor = 0xFFFFFFFF; last.fontSize = 12; last.selected = 0; last.selectedColor = 0xFFFFFFFF; last.selectedBackcroundColor = 0xFF0000FF; last.underlined = 0; last.interactParam = 0; last.rendererIndex = 0; for (int i = 0; i < len; ++i) { if (last.fontSize != tm->current.fontSize) { char tmp[3] = {2, (char)tm->current.fontSize, 0}; result += tmp; last.fontSize = tm->current.fontSize; } if (last.fontColor != tm->current.fontColor) { char tmp[6] = {3, (char)((tm->current.fontColor >> 24) & 0xFF), (char)((tm->current.fontColor >> 16) & 0xFF), (char)((tm->current.fontColor >> 8) & 0xFF), (char)(tm->current.fontColor & 0xFF), 0}; result += tmp; last.fontColor = tm->current.fontColor; } if (last.selectedColor != tm->current.selectedColor) { char tmp[6] = {4, (char)((tm->current.selectedColor >> 24) & 0xFF), (char)((tm->current.selectedColor >> 16) & 0xFF), (char)((tm->current.selectedColor >> 8) & 0xFF), (char)(tm->current.selectedColor & 0xFF), 0}; result += tmp; last.selectedColor = tm->current.selectedColor; } if (last.selectedBackcroundColor != tm->current.selectedBackcroundColor) { char tmp[6] = {5, (char)((tm->current.selectedBackcroundColor >> 24) & 0xFF), (char)((tm->current.selectedBackcroundColor >> 16) & 0xFF), (char)((tm->current.selectedBackcroundColor >> 8) & 0xFF), (char)(tm->current.selectedBackcroundColor & 0xFF), 0}; result += tmp; last.selectedBackcroundColor = tm->current.selectedBackcroundColor; } if (last.underlined != tm->current.underlined) { char tmp[2] = {tm->current.underlined ? (char)1 : (char)7, 0}; result += tmp; last.underlined = tm->current.underlined; } if (last.interactParam != tm->current.interactParam) { char tmp[6] = {8, (char)((tm->current.interactParam >> 24) & 0xFF), (char)((tm->current.interactParam >> 16) & 0xFF), (char)((tm->current.interactParam >> 8) & 0xFF), (char)(tm->current.interactParam & 0xFF), 0}; result += tmp; last.interactParam = tm->current.interactParam; } if (last.rendererIndex != tm->current.rendererIndex) { char tmp[3] = {6, (char)tm->current.rendererIndex, 0}; result += tmp; last.rendererIndex = tm->current.rendererIndex; } if (txt[i] == ' ') { lastPos = i; lastPos2 = result.getLength(); x += tm->zCurrentRenderer()->getTextBreite(" "); result += " "; tm->nextStyle(); continue; } if (txt[i] == '\t') { lastPos = i; lastPos2 = result.getLength(); x += tm->zCurrentRenderer()->getTextBreite("\t"); result += "\t"; tm->nextStyle(); continue; } if (txt[i] == '\n') { x = 0; lastPos = -1; lastPos2 = -1; result += "\n"; tm->nextStyle(); continue; } char buff[2] = {txt[i], 0}; x += tm->zCurrentRenderer()->getTextBreite(buff); result += buff; if (x > maxBr && lastPos > -1) { result.remove(lastPos2, result.getLength()); result += "\n"; result += spacing; x = tm->zCurrentRenderer()->getTextBreite(spacing); i = lastPos; tm->stepTo(lastPos); lastPos = -1; lastPos2 = -1; last = tm->currentStyle(); } tm->nextStyle(); } return result; } void TextFeld::setAutoLineBreakSpacing(const char* spacing) { if (!autoLineBreakSpacing) autoLineBreakSpacing = new Text(); autoLineBreakSpacing->setText(spacing); } // Setzt den Style eines Textabschnittes // begin: die startposition des Abschnittes // end: die endposition des Abschnittes (nicht enthalten) void TextFeld::setTextStyle(int begin, int end, TextStyle style) { tm->setTextStyle(begin, end, style); } void TextFeld::addZeile(const char* zeile) // fügt Zeile An { if (tm->text) { Text* txt = new Text(zeile); if (zeile[txt->getLength() - 1] != '\n') txt->append("\n"); TextRenderer* r = tm->renderer->z(0); if (tm->textStyle.get(tm->textStyle.getEintragAnzahl() - 1) .rendererIndex < tm->renderer->getEintragAnzahl()) r = tm->renderer->z( tm->textStyle.get(tm->textStyle.getEintragAnzahl() - 1) .rendererIndex); if (r) { bool vs = vertikalScrollBar && hatStyle(Style::VScroll); int rbr = (rahmen && hatStyle(Style::Rahmen)) ? rahmen->getRBreite() : 0; r->setSchriftSize( tm->textStyle.get(tm->textStyle.getEintragAnzahl() - 1) .fontSize); r->textFormatieren(txt, gr.x - ((int)vs * 15) - rbr * 2); } lockZeichnung(); tm->text->append(txt->getText()); unlockZeichnung(); txt->release(); if (hatStyle(Style::VScroll)) updateVScroll(); if (hatStyle(Style::HScroll)) updateHScroll(); rend = 1; } } // Fügt eine Zeile an den Text an // zeile: Die neue Zeile // color: Die Farbe der Zeile void TextFeld::addZeile(const char* zeile, int color) { if (tm->text) { Text* txt = new Text(zeile); if (zeile[txt->getLength() - 1] != '\n') txt->append("\n"); TextRenderer* r = tm->renderer->z(0); if (tm->textStyle.get(tm->textStyle.getEintragAnzahl() - 1) .rendererIndex < tm->renderer->getEintragAnzahl()) r = tm->renderer->z( tm->textStyle.get(tm->textStyle.getEintragAnzahl() - 1) .rendererIndex); if (r) { bool vs = vertikalScrollBar && hatStyle(Style::VScroll); int rbr = (rahmen && hatStyle(Style::Rahmen)) ? rahmen->getRBreite() : 0; r->setSchriftSize( tm->textStyle.get(tm->textStyle.getEintragAnzahl() - 1) .fontSize); r->textFormatieren(txt, gr.x - ((int)vs * 15) - rbr * 2); } lockZeichnung(); tm->text->append(txt->getText()); setSchriftFarbe(tm->text->getLength() - txt->getLength(), tm->text->getLength(), color); unlockZeichnung(); txt->release(); if (hatStyle(Style::VScroll)) updateVScroll(); if (hatStyle(Style::HScroll)) updateHScroll(); rend = 1; } } // Deselectiert alle textabschnitte void TextFeld::deselectAuswahl() { for (int i = 0; i < tm->textStyle.getEintragAnzahl(); i++) { TextStyle s = tm->textStyle.get(i); if (s.selected) { s.selected = 0; tm->textStyle.set(s, i); } } tm->cleanupStyles(); } void TextFeld::setAuswahl(int pos1, int pos2) // setzt den Ausgewählten Text { deselectAuswahl(); TextStyle s = tm->getTextStyle(pos1); s.selected = 1; tm->setTextStyle(pos1, pos2, s); } void TextFeld::setAuswahl(Punkt& auswahl) { deselectAuswahl(); TextStyle s = tm->getTextStyle(auswahl.x); s.selected = 1; tm->setTextStyle(auswahl.x, auswahl.y, s); rend = 1; } void TextFeld::addAuswahl(int pos1, int pos2) { TextStyle s = tm->getTextStyle(pos1); s.selected = 1; tm->setTextStyle(pos1, pos2, s); } void TextFeld::addAuswahl(Punkt& auswahl) { TextStyle s = tm->getTextStyle(auswahl.x); s.selected = 1; tm->setTextStyle(auswahl.x, auswahl.y, s); rend = 1; } // Setzt den ausgewählten textabschnitt fest // begin: Die Cursorposition im Text // end: Die Position im Text, bis zu der der Text eingefärbt werden soll void TextFeld::invertAuswahl(int begin, int end) { for (int i = begin; i < end; i++) { TextStyle s = tm->getTextStyle(i); s.selected = !s.selected; tm->setTextStyle(i, i + 1, s); rend = 1; } } // ersetzt alle ausgewählten Textabschnitte mit einem text // text: der neue Text void TextFeld::replaceAuswahl(const char* text) { tm->cleanupStyles(); int sa = tm->textStyle.getEintragAnzahl(); int last = tm->text->getLength(); int si = 0; for (int i = sa - 1; i >= 0; i--) { TextStyle s = tm->textStyle.get(i); si = i; if (s.selected) { if ((i > 0 && !tm->textStyle.get(i - 1).selected) || i == 0) { s.selected = false; tm->textStyle.set(s, si); tm->removeText(s.beginIndex, last); tm->insertText(s.beginIndex, text); } } else last = s.beginIndex; } } void TextFeld::setTextRendererZ(TextRenderer* textRd) { if (tm->renderer) tm->renderer->leeren(); else tm->renderer = new RCArray(); tm->renderer->add(textRd); rend = 1; } // Fügt einen TextRenderer hinzu // textRd: Der Textrenderer void TextFeld::addTextRendererZ(TextRenderer* textRd) { if (!tm->renderer) tm->renderer = new RCArray(); tm->renderer->add(textRd); } // Setzt die verwendeten TextRenderer // textRd: Die Textrenderer void TextFeld::setTextRendererZ(RCArray* textRd) { if (tm->renderer) tm->renderer->release(); tm->renderer = textRd; } void TextFeld::setSchriftZ(Schrift* schrift) // setzt einen Zeiger zur Schrift { if (!tm->renderer) tm->renderer = new RCArray(); if (!tm->renderer->getEintragAnzahl()) tm->renderer->add(new TextRenderer(schrift)); else tm->renderer->z(0)->setSchriftZ(schrift); rend = 1; } // Setzt einen Zeiger zur Schrift // rendererIndex: Der Index des Renderers dessen Schrift gesetzt werden soll // schrift: Die Schrift, die zum Textzeichnen verwendet werden soll. void TextFeld::setSchriftZ(int rendererIndex, Schrift* schrift) { if (!tm->renderer) tm->renderer = new RCArray(); if (tm->renderer->getEintragAnzahl() <= rendererIndex) tm->renderer->add(new TextRenderer(schrift), rendererIndex); else tm->renderer->z(rendererIndex)->setSchriftZ(schrift); } void TextFeld::setSchriftSize(unsigned char gr) // setzt die Schriftgröße { TextStyle s = tm->textStyle.get(0); s.fontSize = gr; tm->textStyle.set(s, 0); rend = 1; } // Setzt die Schriftgröße (Standart: 12) // begin: Der Index des ersten betroffenen Zeichens // end: Der Index des ersten nicht betroffenen Zeichens // gr: Die Schriftgröße, die zum Textzeichnen verwendet werden soll void TextFeld::setSchriftSize(int begin, int end, unsigned char gr) { TextStyle s = tm->getTextStyle(begin); s.fontSize = gr; tm->setTextStyle(begin, end, s); rend = 1; } void TextFeld::setSchriftFarbe(int fc) // setzt die Schrift Farbe { TextStyle s = tm->textStyle.get(0); s.fontColor = fc; tm->textStyle.set(s, 0); rend = 1; } // Setzt die Schrift Farbe // begin: Der Index des ersten betroffenen Zeichens // end: Der Index des ersten nicht betroffenen Zeichens // fc: Die Farbe, die zum Textzeichnen verwendet werden soll void TextFeld::setSchriftFarbe(int begin, int end, int fc) { TextStyle s = tm->getTextStyle(begin); s.fontColor = fc; tm->setTextStyle(begin, end, s); rend = 1; } void TextFeld::setSchowChar(unsigned char c) // bei Passwortfeld * { showChar = c; rend = 1; } void TextFeld::setVScrollZuZeile(int zeile) // scrollt zur Zeile { if (vertikalScrollBar && tm->renderer && tm->renderer->getEintragAnzahl() && tm->text && hatStyle(Style::Mehrzeilig)) { lockZeichnung(); tm->resetIteration(); int len = tm->text->getLength(); int y = 0; int lnum = 0; const char* text = tm->text->getText(); Text txtWithLineBreaks; if (hatStyle(Style::AutoLineBreak)) { txtWithLineBreaks = addLineBreaksToText(tm->text->getText(), autoLineBreakSpacing ? autoLineBreakSpacing->getText() : ""); text = txtWithLineBreaks; len = txtWithLineBreaks.getLength(); } int max = 0; for (int i = 0; i < len && lnum < zeile; i++) { if (text[i] == '\n') { lnum++; y += max; max = 0; tm->nextStyle(); continue; } TextRenderer* r = tm->zCurrentRenderer(); if (r) { int tmp = r->getZeilenabstand() + r->getZeilenHeight(); max = max >= tmp ? max : tmp; } tm->nextStyle(); } unlockZeichnung(); vertikalScrollBar->scroll(y); rend = 1; } } void TextFeld::updateVScroll(int pos) // scrollt nach unten { if (pos == -1) pos = cpos; if (vertikalScrollBar) { int sPos = 0; int hi = 0; int sPosZH = 0; if (tm->text && tm->renderer) { if (hatStyleNicht(Style::Mehrzeilig)) tm->text->remove('\n'); hi = gr.y; if (hatStyle(Style::Rahmen) && rahmen) hi -= rahmen->getRBreite() * 2; if (hatStyle(Style::HScroll) && horizontalScrollBar) hi -= 15; int th = 0; lockZeichnung(); tm->resetIteration(); int len = tm->text->getLength(); const char* text = tm->text->getText(); Text txtWithLineBreaks; if (hatStyle(Style::AutoLineBreak)) { txtWithLineBreaks = addLineBreaksToText(tm->text->getText(), autoLineBreakSpacing ? autoLineBreakSpacing->getText() : ""); text = txtWithLineBreaks; len = txtWithLineBreaks.getLength(); } int max = 0; int lastMax = 0; for (int i = 0; i < len; i++) { if (text[i] == '\n') { if (i <= pos) { sPos += max; sPosZH = max; } th += max; lastMax = max; max = 0; tm->nextStyle(); continue; } TextRenderer* r = tm->zCurrentRenderer(); if (r) { int tmp = r->getZeilenabstand() + r->getZeilenHeight(); max = max >= tmp ? max : tmp; } tm->nextStyle(); } if (max != lastMax && max > 0) { th += max; lastMax = max; } th += lastMax; unlockZeichnung(); vertikalScrollBar->update(th, hi); } if (sPos - sPosZH < vertikalScrollBar->getScroll()) vertikalScrollBar->scroll(sPos - sPosZH); if (sPos + sPosZH > vertikalScrollBar->getScroll() + vertikalScrollBar->getScrollData()->anzeige) vertikalScrollBar->scroll(sPos + sPosZH * 2 - hi); rend = 1; } } void TextFeld::updateHScroll(int pos) // scrollt zur Curser Position { if (pos == -1) pos = cpos; lockZeichnung(); if (horizontalScrollBar && tm->text && tm->renderer) { if (hatStyleNicht(Style::Mehrzeilig)) tm->text->remove('\n'); int br = gr.x; if (hatStyle(Style::Rahmen) && rahmen) br -= rahmen->getRBreite() * 2; if (hatStyle(Style::VScroll) && vertikalScrollBar) br -= 15; tm->resetIteration(); int maxBr = 0; int len = tm->text->getLength(); const char* text = tm->text->getText(); int lineBr = 0; char buff[] = {0, 0}; int cbr = 0; for (int i = 0; i < len; i++) { buff[0] = text[i]; if (text[i] == '\n') { maxBr = maxBr >= lineBr ? maxBr : lineBr; lineBr = 0; tm->nextStyle(); continue; } TextRenderer* r = tm->zCurrentRenderer(); if (r) { lineBr += r->getTextBreite(buff); if (i <= pos) cbr = lineBr; } tm->nextStyle(); } maxBr = maxBr >= lineBr ? maxBr : lineBr; horizontalScrollBar->update(maxBr, br); if (cbr > horizontalScrollBar->getScroll() + horizontalScrollBar->getScrollData()->anzeige) horizontalScrollBar->scroll(cbr - br); if (cbr < horizontalScrollBar->getScroll()) horizontalScrollBar->scroll(cbr); } unlockZeichnung(); } // Gibt die breite in pixeln zurück, die benötigt wird um den aktuellen text mit // den aktuellen styles voll anzuzeigen int TextFeld::getNeededWidth() { int maxBr = 0; lockZeichnung(); if (tm->text && tm->renderer) maxBr = getTextWidth(); unlockZeichnung(); bool vs = vertikalScrollBar && hatStyle(Style::VScroll); bool r = rahmen && hatStyle(Style::Rahmen); return maxBr + (r ? rahmen->getRBreite() * 2 : 0) + (vs ? 15 : 0); } // Gibt die höhe in pixeln zurück, die benötigt wird um den aktuellen text mit // den aktuellen styles voll anzuzeigen int TextFeld::getNeededHeight() { int th = 0; lockZeichnung(); if (tm->text && tm->renderer) th = getTextHeight(); unlockZeichnung(); bool hs = horizontalScrollBar && hatStyle(Style::HScroll); bool r = rahmen && hatStyle(Style::Rahmen); return th + (r ? rahmen->getRBreite() * 2 : 0) + (hs ? 15 : 0); } bool TextFeld::tick(double tickval) // tick { if (hatStyle(Style::Fokus)) { if (tickVal < 0.5 && tickVal + tickval >= 0.5) rend = 1; if (tickVal >= 0.5 && tickVal + tickval >= 1) rend = 1; tickVal += tickval; if (tickVal >= 1) tickVal -= 1; } return ZeichnungHintergrund::tick(tickval); } void TextFeld::doTastaturEreignis(TastaturEreignis& te) { bool ntakc = !te.verarbeitet; if (te.verarbeitet || hatStyleNicht(Style::Fokus)) return; if (!tak) return; getThis(); if (tak(takParam, this, te)) { if (hatStyleNicht(Style::Editierbar)) { release(); return; } if (te.id == TE_Press) { bool shift = getTastenStand(T_Shift); bool strg = getTastenStand(T_Strg); switch (te.virtualKey) { case T_Entf: if (!tm->getTextStyle(cpos).selected) tm->removeText(cpos, cpos + 1); else { cpos = tm->getTextStyle(cpos).beginIndex; while (cpos > 0 && tm->getTextStyle(cpos - 1).selected) cpos = tm->getTextStyle(cpos - 1).beginIndex; } replaceAuswahl(""); deselectAuswahl(); rend = 1; break; case T_BackSpace: if (!tm->getTextStyle(cpos).selected) { tm->removeText(cpos - 1, cpos); cpos--; } else { cpos = tm->getTextStyle(cpos).beginIndex; while (cpos > 0 && tm->getTextStyle(cpos - 1).selected) cpos = tm->getTextStyle(cpos - 1).beginIndex; } replaceAuswahl(""); deselectAuswahl(); rend = 1; break; case T_Enter: if (hatStyle(TextFeld::Style::Mehrzeilig)) { if (!tm->getTextStyle(cpos).selected) tm->insertText(cpos, "\n"); else { cpos = tm->getTextStyle(cpos).beginIndex; while (cpos > 0 && tm->getTextStyle(cpos - 1).selected) cpos = tm->getTextStyle(cpos - 1).beginIndex; } replaceAuswahl("\n"); ++cpos; rend = 1; } break; case T_Links: if (shift) { if (strg) { int tmp = tm->text->getLKick(cpos); invertAuswahl(tmp, cpos); cpos = tmp; } else { invertAuswahl(cpos - 1, cpos); --cpos; } } else { if (strg) cpos = tm->text->getLKick(cpos); else --cpos; deselectAuswahl(); } rend = 1; break; case T_Oben: { int tmp = tm->text->getOKick(cpos); invertAuswahl(tmp, cpos); cpos = tmp; if (!shift) deselectAuswahl(); rend = 1; break; } case T_Rechts: if (shift) { if (strg) { int tmp = tm->text->getRKick(cpos); invertAuswahl(cpos, tmp); cpos = tmp; } else { invertAuswahl(cpos, cpos + 1); ++cpos; } } else { if (strg) cpos = tm->text->getRKick(cpos); else ++cpos; deselectAuswahl(); } rend = 1; break; case T_Unten: { int tmp = tm->text->getUKick(cpos); invertAuswahl(cpos, tmp); cpos = tmp; if (!shift) deselectAuswahl(); rend = 1; break; } default: if (strg && te.id == TE_Press) { if (te.virtualKey == 'c' || te.virtualKey == 'C') { int sa = tm->textStyle.getEintragAnzahl(); int length = 0; for (int i = 0; i < sa; i++) { TextStyle s = tm->textStyle.get(i); if (s.selected) { int max = tm->text->getLength(); if (i < sa - 1) max = tm->textStyle.get(i + 1).beginIndex; length += max - s.beginIndex; } } if (length) { char* txt = new char[length + 1]; txt[length] = 0; int index = 0; for (int i = 0; i < sa; i++) { TextStyle s = tm->textStyle.get(i); if (s.selected) { int max = tm->text->getLength(); if (i < sa - 1) max = tm->textStyle.get(i + 1) .beginIndex; memcpy(txt + index, tm->text->getText() + s.beginIndex, max - s.beginIndex); index += max - s.beginIndex; } } TextKopieren(txt); delete[] txt; } else TextKopieren(tm->text->getText()); } if (te.virtualKey == 'v' || te.virtualKey == 'V') { const char* txt = TextInsert(); if (!tm->getTextStyle(cpos).selected) tm->insertText(cpos, txt); else { cpos = tm->getTextStyle(cpos).beginIndex; while ( cpos > 0 && tm->getTextStyle(cpos - 1).selected) cpos = tm->getTextStyle(cpos - 1).beginIndex; } replaceAuswahl(txt); cpos += textLength(txt); rend = 1; } break; } if (istSchreibbar(te.taste[0])) { if (!tm->getTextStyle(cpos).selected) tm->insertText(cpos, te.taste); else { cpos = tm->getTextStyle(cpos).beginIndex; while (cpos > 0 && tm->getTextStyle(cpos - 1).selected) cpos = tm->getTextStyle(cpos - 1).beginIndex; } replaceAuswahl(te.taste); ++cpos; rend = 1; } break; } } if (cpos < 0) cpos = 0; if (cpos > tm->text->getLength()) cpos = tm->text->getLength(); if (hatStyle(Style::VScroll)) updateVScroll(cpos); if (hatStyle(Style::HScroll)) updateHScroll(cpos); te.verarbeitet = 1; } if (ntakc && te.verarbeitet && nTak) te.verarbeitet = nTak(ntakParam, this, te); release(); } void TextFeld::render(Bild& zRObj) // zeichenet nach zRObj { if (hatStyleNicht(Style::Sichtbar)) return; ZeichnungHintergrund::render(zRObj); if (!tm->text || !tm->renderer) return; lockZeichnung(); if (!zRObj.setDrawOptions(innenPosition, innenSize)) { unlockZeichnung(); return; } if (hatStyleNicht(Style::Mehrzeilig)) tm->text->remove('\n'); int tbr = getTextWidth(); int thi = getTextHeight(); int xxx = 0; int yyy = 0; int breite = innenSize.x; int height = innenSize.y; bool hs = horizontalScrollBar && hatStyle(Style::HScroll); bool vs = vertikalScrollBar && hatStyle(Style::VScroll); if (vs) yyy -= vertikalScrollBar->getScroll(); if (hs) xxx -= horizontalScrollBar->getScroll(); if (hatStyle(Style::HCenter) && !hs) xxx = (breite / 2) - tbr / 2; int x = xxx; int len = tm->text->getLength(); const char* text = tm->text->getText(); Text txtWithLineBreaks; if (hatStyle(Style::AutoLineBreak)) { txtWithLineBreaks = addLineBreaksToText(tm->text->getText(), autoLineBreakSpacing ? autoLineBreakSpacing->getText() : ""); text = txtWithLineBreaks; len = txtWithLineBreaks.getLength(); } lockZeichnung(); tm->resetIteration(); if (thi == 0) { thi = tm->zCurrentRenderer()->getZeilenHeight(); } if (hatStyle(Style::VCenter) && !vs) yyy = (height / 2) - thi / 2; int y = yyy; TextStyle& style = tm->currentStyle(); int maxLH = 0; int corrector = 0; int realLen = tm->text->getLength(); for (int i = 0; i <= len; i++) { int oldX = x; if (i < len && tm->zCurrentRenderer()) tm->zCurrentRenderer()->renderChar(x, y, istSchreibbar(showChar) ? showChar : text[i], zRObj, style.selected ? style.selectedColor : style.fontColor, style.underlined, style.selected, style.selectedBackcroundColor); if (i - corrector == cpos && tickVal <= 0.5 && hatStyle(Style::Fokus) && hatStyle(Style::Editierbar) && tm->zCurrentRenderer()) zRObj.drawLinieV( oldX, y, tm->zCurrentRenderer()->getZeilenHeight(), 0xFFFF5555); if (i >= realLen || text[i] != tm->text->getText()[i]) { corrector++; } if (tm->zCurrentRenderer()) { int tmp = tm->zCurrentRenderer()->getZeilenHeight() + tm->zCurrentRenderer()->getZeilenAbstand(); maxLH = tmp > maxLH ? tmp : maxLH; } if (i < len && text[i] == '\n') { x = xxx; y += maxLH; } tm->nextStyle(); } unlockZeichnung(); zRObj.releaseDrawOptions(); unlockZeichnung(); } // Konstant Text* TextFeld::getText() const // gibt vom Text zurück { if (!tm->text) return 0; return dynamic_cast(tm->text->getThis()); } Text* TextFeld::zText() const // gibt den Text zurück { return tm->text; } Schrift* TextFeld::getSchrift() const // gint getThis der Schrift Zurück { tm->resetIteration(); return tm->zCurrentRenderer() ? tm->zCurrentRenderer()->getSchrift() : 0; } Schrift* TextFeld::zSchrift() const // gibt die Schrift zurück { tm->resetIteration(); return tm->zCurrentRenderer() ? tm->zCurrentRenderer()->zSchrift() : 0; } // Gibt die Schrift zurück. // rendererIndex: Der Index des Renderers dessen Schrift zurückgegeben werden // soll return: 0, falls die Schrift nicht gesetzt wurde Schrift* TextFeld::getSchrift(int rendererIndex) const { if (tm->renderer && tm->renderer->z(rendererIndex)) return tm->renderer->z(rendererIndex)->getSchrift(); return 0; } // Gibt die Schrift ohne erhöhten Reference Counter zurük // rendererIndex: Der Index des Renderers dessen Schrift zurückgegeben werden // soll return: 0, falls die Schrift nicht gesetzt wurde Schrift* TextFeld::zSchrift(int rendererIndex) const { if (tm->renderer && tm->renderer->z(rendererIndex)) return tm->renderer->z(rendererIndex)->zSchrift(); return 0; } TextRenderer* TextFeld::getTextRenderer() const { tm->resetIteration(); return dynamic_cast(tm->zCurrentRenderer()->getThis()); } TextRenderer* TextFeld::zTextRenderer() const { tm->resetIteration(); return tm->zCurrentRenderer(); } // Gibt den TextRenderer zurück. // index: Der Index des Renderers der zurückgegeben werden soll // return: 0, falls der TextRenderer nicht gesetzt wurde TextRenderer* TextFeld::getTextRenderer(int index) const { if (tm->renderer && tm->renderer->z(index)) return tm->renderer->get(index); return 0; } // Gibt dien TextRenderer ohne erhöhten Reference Counter zurük // index: Der Index des Renderers der zurückgegeben werden soll // return: 0, falls der TextRenderer nicht gesetzt wurde TextRenderer* TextFeld::zTextRenderer(int index) const { if (tm->renderer && tm->renderer->z(index)) return tm->renderer->z(index); return 0; } unsigned char TextFeld::getSchriftSize() const // gibt die Schriftgröße zurück { tm->resetIteration(); return tm->current.fontSize; } // Gibt die Schriftgröße zurück // index: Der Index des Zeichens unsigned char TextFeld::getSchriftSize(int index) const { tm->resetIteration(); return tm->current.fontSize; } int TextFeld::getSchriftFarbe() const // gibt getThis der Schriftfarbe zurück { tm->resetIteration(); return tm->current.fontColor; } // Gibt die Schriftfarbe im A8R8G8B8 Format zurück // index: Der Index des Zeichens int TextFeld::getSchriftFarbe(int index) const { return tm->getTextStyle(index).fontColor; } unsigned char TextFeld::getShowChar() const // gibt den Anzeige Char zurück { return showChar; } int TextFeld::getCursorPos() const { return cpos; } // Gibt 1 zurück wenn das Zeichen ausgewählt ist // index: Der Index des Zeichens bool TextFeld::isCharSelected(int index) const { return tm->getTextStyle(index).selected; } // Gibt den Index des Zeichens zurück, das sich unter der Maus befindet // mx: die x position der maus relativ zur position des textfeldes // my: die y position der maus relativ zut position des textfeldes // return: -1, falls sich an der Position kein zeichen befindet int TextFeld::getTextIndexAt(int mx, int my) const { if (!tm || !tm->text || !tm->zCurrentRenderer()) return -1; int tbr = getTextWidth(); int thi = getTextHeight(); int xxx = 0; int yyy = 0; int breite = innenSize.x; int height = innenSize.y; bool hs = horizontalScrollBar && hatStyle(Style::HScroll); bool vs = vertikalScrollBar && hatStyle(Style::VScroll); if (vs) yyy -= vertikalScrollBar->getScroll(); if (hs) xxx -= horizontalScrollBar->getScroll(); if (hatStyle(Style::HCenter) && !hs) xxx = (breite / 2) - tbr / 2; if (hatStyle(Style::VCenter) && !vs) yyy = (height / 2) - thi / 2; int x = xxx; int y = yyy; int len = tm->text->getLength(); const char* text = tm->text->getText(); Text txtWithLineBreaks; if (hatStyle(Style::AutoLineBreak)) { txtWithLineBreaks = addLineBreaksToText(tm->text->getText(), autoLineBreakSpacing ? autoLineBreakSpacing->getText() : ""); text = txtWithLineBreaks; len = txtWithLineBreaks.getLength(); } tm->resetIteration(); int corrector = 0; int maxLH = 0; int realLen = tm->text->getLength(); for (int i = 0; i < len; i++) { if (i >= realLen || text[i] != tm->text->getText()[i]) { corrector++; } char buff[2] = {istSchreibbar(showChar) ? (char)showChar : text[i], 0}; int tmpx = tm->zCurrentRenderer()->getTextBreite(buff); int tmpy = tm->zCurrentRenderer()->getZeilenHeight(); if (mx >= x && mx < x + tmpx && my >= y && my < y + tmpy) return i - corrector; if (mx < x + tmpx && my < y + tmpy) return -1; x += tmpx; tmpy += tm->zCurrentRenderer()->getZeilenAbstand(); maxLH = tmpy > maxLH ? tmpy : maxLH; if (text[i] == '\n') { x = xxx; y += maxLH; } tm->nextStyle(); } return -1; } // Gibt den Index des Zeichens zurück, vor dem der curser gesetzt wird, wenn mit // der maus geklickt wird // mx: die x position der maus relativ zur position des textfeldes // my: die y position der maus relativ zut position des textfeldes int TextFeld::getCurserPosAt(int mx, int my) const { if (!tm || !tm->text || !tm->zCurrentRenderer()) return tm->text->getLength(); int tbr = getTextWidth(); int thi = getTextHeight(); int xxx = 0; int yyy = 0; int breite = innenSize.x; int height = innenSize.y; bool hs = horizontalScrollBar && hatStyle(Style::HScroll); bool vs = vertikalScrollBar && hatStyle(Style::VScroll); if (vs) yyy -= vertikalScrollBar->getScroll(); if (hs) xxx -= horizontalScrollBar->getScroll(); if (hatStyle(Style::HCenter) && !hs) xxx = (breite / 2) - tbr / 2; if (hatStyle(Style::VCenter) && !vs) yyy = (height / 2) - thi / 2; int x = xxx; int y = yyy; int len = tm->text->getLength(); const char* text = tm->text->getText(); Text txtWithLineBreaks; if (hatStyle(Style::AutoLineBreak)) { txtWithLineBreaks = addLineBreaksToText(tm->text->getText(), autoLineBreakSpacing ? autoLineBreakSpacing->getText() : ""); text = txtWithLineBreaks; len = txtWithLineBreaks.getLength(); } tm->resetIteration(); int maxLH = 0; int realLen = tm->text->getLength(); int corrector = 0; for (int i = 0; i < len; i++) { if (i >= realLen || text[i] != tm->text->getText()[i]) { corrector++; } int tmpx = tm->zCurrentRenderer()->getCharWidth( istSchreibbar(showChar) ? showChar : text[i]); int tmpy = tm->zCurrentRenderer()->getZeilenHeight() + tm->zCurrentRenderer()->getZeilenAbstand(); if (mx < x + tmpx / 2 && my < y + tmpy - tm->zCurrentRenderer()->getZeilenAbstand() / 2) return i - corrector; x += tmpx + tm->zCurrentRenderer()->getZeichenAbstand(); maxLH = tmpy > maxLH ? tmpy : maxLH; if (text[i] == '\n') { if (my >= y - tm->zCurrentRenderer()->getZeilenAbstand() / 2 && my < y + maxLH - tm->zCurrentRenderer()->getZeilenAbstand() / 2) return i - corrector; x = xxx; y += maxLH; } tm->nextStyle(); } return tm->text->getLength(); } // Gibt den Style eines bestimmten zeichens zurück // index: Der index des Zeichensf TextStyle TextFeld::getTextStyle(int index) const { return tm->getTextStyle(index); } // gibt die Zeichenkette zurück, die bei Verwendung des Styles // AutoLineBreak nach jedem Zeilenumbruch eingefügt wird Text TextFeld::getAutoLineBreakSpacing() const { return autoLineBreakSpacing ? *autoLineBreakSpacing : Text(""); } Zeichnung* TextFeld::dublizieren() const // Erzeugt eine Kopie des Zeichnungs { TextFeld* obj = new TextFeld(); obj->setPosition(pos); obj->setSize(gr); obj->setMausEreignisParameter(makParam); obj->setTastaturEreignisParameter(takParam); obj->setMausEreignis(mak); obj->setTastaturEreignis(tak); if (toolTip) obj->setToolTipZ((ToolTip*)toolTip->dublizieren()); obj->setStyle(style); obj->tm->renderer->release(); obj->tm->renderer = dynamic_cast*>(tm->renderer->getThis()); obj->tm->textStyle.leeren(); for (const auto& i : tm->textStyle) obj->tm->textStyle.add(i); obj->tm->index = tm->index; obj->tm->styleIndex = tm->styleIndex; obj->tm->current = tm->current; if (tm->text) obj->setText(tm->text->getText()); obj->setHintergrundFarbe(hintergrundFarbe); if (hintergrundFeld) obj->setAlphaFeldZ((AlphaFeld*)hintergrundFeld->dublizieren()); if (rahmen) obj->setRahmenZ((Rahmen*)rahmen->dublizieren()); if (hintergrundBild) obj->setHintergrundBild( dynamic_cast(hintergrundBild->getThis())); if (vertikalScrollBar) { obj->setVertikalKlickScroll(vertikalScrollBar->getKlickScroll()); obj->setVertikalScrollPos(vertikalScrollBar->getScroll()); obj->setVertikalScrollFarbe( vertikalScrollBar->getFarbe(), vertikalScrollBar->getBgFarbe()); } if (horizontalScrollBar) { obj->setHorizontalKlickScroll(horizontalScrollBar->getKlickScroll()); obj->setHorizontalScrollPos(horizontalScrollBar->getScroll()); obj->setHorizontalScrollFarbe( horizontalScrollBar->getFarbe(), horizontalScrollBar->getBgFarbe()); } if (autoLineBreakSpacing) { obj->setAutoLineBreakSpacing(*autoLineBreakSpacing); } obj->setSchowChar(showChar); return obj; }