#include "TextFeld.h"
#include "Schrift.h"
#include "Text.h"
#include "AlphaFeld.h"
#include "Rahmen.h"
#include "Bild.h"
#include "TastaturEreignis.h"
#include "MausEreignis.h"
#include "Fenster.h"
#include "Scroll.h"
#include <math.h>
#include "Globals.h"
#include "ToolTip.h"
#include "Scroll.h"

using namespace Framework;


bool TextFeld::TextStyle::operator==( 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;
}


TextFeld::TextStyleManager::TextStyleManager()
    : ReferenceCounter(),
    renderer( new RCArray< TextRenderer >() ),
    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, TextFeld::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 ) == 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
TextFeld::TextStyle &TextFeld::TextStyleManager::currentStyle()
{
    return current;
}

// gibt den aktuellen text renderer zurück
TextRenderer *TextFeld::TextStyleManager::zCurrentRenderer()
{
    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
TextFeld::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() ),
    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();
}

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 = TastenStand[ T_Shift ];
        bool strg = TastenStand[ 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();
    char *text = tm->text->getText();
    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();
    char *text = tm->text->getText();
    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< void( int, int, MausEreignis me ) > 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;
    int lastPos = -1;
    int lastPos2 = -1;
    int x = 0;
    const char *txt = tm->text->getText();
    Text result = "";
    int len = tm->text->getLength();
    lockZeichnung();
    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();
    }
    unlockZeichnung();
    setFormattedText( result );
}

// 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< TextRenderer >();
    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< TextRenderer >();
    tm->renderer->add( textRd );
}

// Setzt die verwendeten TextRenderer
//  textRd: Die Textrenderer
void TextFeld::setTextRendererZ( RCArray< TextRenderer > *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< TextRenderer >();
    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< TextRenderer >();
    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;
        char *text = tm->text->getText();
        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();
            char *text = tm->text->getText();
            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();
        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();
    return maxBr;
}

// 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();
    return th;
}

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 = TastenStand[ T_Shift ];
            bool strg = TastenStand[ T_Strg ];
            switch( te.taste )
            {
            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( !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.taste == 'c' || te.taste == '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.taste == 'v' || te.taste == 'V' )
                    {
                        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 ) )
                {
                    char buff[] = { (char)te.taste, 0 };
                    if( !tm->getTextStyle( cpos ).selected )
                        tm->insertText( cpos, buff );
                    else
                    {
                        cpos = tm->getTextStyle( cpos ).beginIndex;
                        while( cpos > 0 && tm->getTextStyle( cpos - 1 ).selected )
                            cpos = tm->getTextStyle( cpos - 1 ).beginIndex;
                    }
                    replaceAuswahl( buff );
                    ++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;
    if( hatStyle( Style::VCenter ) && !vs )
        yyy = ( height / 2 ) - thi / 2;
    int x = xxx;
    int y = yyy;
    int len = tm->text->getLength();
    char *text = tm->text->getText();
    lockZeichnung();
    tm->resetIteration();
    TextStyle &style = tm->currentStyle();
    int maxLH = 0;
    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 == cpos && tickVal <= 0.5 && hatStyle( Style::Fokus ) && hatStyle( Style::Editierbar ) && tm->zCurrentRenderer() )
            zRObj.drawLinieV( oldX, y, tm->zCurrentRenderer()->getZeilenHeight(), 0xFFFF5555 );
        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<Text *>( 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<TextRenderer *>( 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();
    char *text = tm->text->getText();
    tm->resetIteration();
    int maxLH = 0;
    for( int i = 0; i < len; i++ )
    {
        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;
        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();
    char *text = tm->text->getText();
    tm->resetIteration();
    int maxLH = 0;
    for( int i = 0; i < len; i++ )
    {
        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;
        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;
            x = xxx;
            y += maxLH;
        }
        tm->nextStyle();
    }
    return tm->text->getLength();
}

// Gibt den Style eines bestimmten zeichens zurück
//  index: Der index des Zeichensf
TextFeld::TextStyle TextFeld::getTextStyle( int index ) const
{
    return tm->getTextStyle( index );
}

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<RCArray<TextRenderer> *>( tm->renderer->getThis() );
    obj->tm->textStyle.leeren();
    for( 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<Bild *>( 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() );
    }
    obj->setSchowChar( showChar );
    return obj;
}