#include "List.h"

#include "AlphaField.h"
#include "Array.h"
#include "Border.h"
#include "Font.h"
#include "Globals.h"
#include "Image.h"
#include "KeyboardEvent.h"
#include "MouseEvent.h"
#include "Scroll.h"
#include "Text.h"
#include "TextField.h"

using namespace Framework;

// Contents of the SelectionList class from List.h
// Constructor
SelectionList::SelectionList()
    : DrawableBackground(),
      tfListe(0),
      selection(-1),
      ahColor(0xFF000000),
      ahImage(0),
      aBuffer(0),
      aBorder(0),
      styles(0),
      ahColorListe(0),
      ahImageListe(0),
      aBufferListe(0),
      aBorderList(0),
      font(0)
{
    style = 0;
    this->setMouseEvent(_ret1ME);
    this->setKeyboardEvent(_ret1TE);
}

// Destructor
SelectionList::~SelectionList()
{
    if (tfListe) tfListe->release();
    if (ahImage) ahImage->release();
    if (aBuffer) aBuffer->release();
    if (aBorder) aBorder->release();
    if (styles) styles->release();
    if (ahColorListe) ahColorListe->release();
    if (ahImageListe) ahImageListe->release();
    if (aBufferListe) aBufferListe->release();
    if (aBorderList) aBorderList->release();
    if (font) font->release();
}

void SelectionList::doMouseEvent(MouseEvent& me, bool userRet)
{
    if (!userRet || hasStyleNot(Style::Allowed)) return;
    if (DrawableBackground::hasStyle(Style::VScroll) && vertikalScrollBar)
    {
        int rbr = 0;
        if (border && DrawableBackground::hasStyle(Style::Border))
            rbr = border->getRWidth();
        if (((me.mx > gr.x - 15 - rbr) || me.id == ME_UScroll
                || me.id == ME_DScroll)
            && me.id != ME_Enter && me.id != ME_Leaves)
        {
            vertikalScrollBar->doMouseMessage(
                gr.x - rbr - 15, rbr, 15, gr.y - rbr * 2, me);
            me.processed = 1;
        }
    }
    if (!me.processed && me.id == ME_RLeft)
    {
        int eintr = getClickEntry(me.my);
        if (eintr >= 0)
        {
            if (hasStyleNot(Style::MultiSelect))
            {
                selection = eintr;
                rend = 1;
            }
            else
            {
                bool shift = getKeyState(T_Shift);
                bool strg = getKeyState(T_Strg);
                if (strg)
                {
                    setMsStyle(eintr,
                        Style::Selected,
                        hasMsStyleNot(eintr, Style::Selected));
                    selection = eintr;
                }
                else if (shift && selection != -1)
                {
                    deselect();
                    int beg = selection, end = eintr;
                    if (beg > end)
                    {
                        int tmp = end;
                        end = beg;
                        beg = tmp;
                    }
                    for (int i = beg; i <= end; ++i)
                    {
                        addMsStyle(i, Style::Selected);
                    }
                }
                else
                {
                    deselect();
                    addMsStyle(eintr, Style::Selected);
                    selection = eintr;
                }
            }
        }
        else
            deselect();
    }
    me.processed = 1;
}

bool SelectionList::hasStyle(int styleSet, int styleCheck) const
{
    return (styleSet | styleCheck) == styleSet;
}

// non-constant
void SelectionList::update() // updates the selection list
{
    int rbr = 0;
    if (border)
    {
        rbr = border->getRWidth();
        border->setPosition(0, 0);
        border->setSize(gr.x, gr.y);
    }
    if (backgroundFeld)
    {
        backgroundFeld->setPosition(rbr, rbr);
        backgroundFeld->setSize(gr.x - rbr * 2, gr.y - rbr * 2);
    }
    if (hasStyleNot(Style::MultiStyled) && tfListe)
    {
        bool FieldBorder = DrawableBackground::hasStyle(Style::FieldBorder);
        bool FieldBackground
            = DrawableBackground::hasStyle(Style::FieldBackground);
        bool FieldHImage = DrawableBackground::hasStyle(Style::FieldBImage);
        bool FieldHAlpha = DrawableBackground::hasStyle(Style::FieldBAlpha);
        bool FieldBuffer = DrawableBackground::hasStyle(Style::FieldBuffer);
        for (TextField* tf : *tfListe)
        {
            tf->setStyle(TextField::Style::Border, FieldBorder);
            tf->setStyle(TextField::Style::Background, FieldBackground);
            tf->setStyle(TextField::Style::BImage, FieldHImage);
            tf->setStyle(TextField::Style::BAlpha, FieldHAlpha);
            tf->setStyle(TextField::Style::Buffered, FieldBuffer);
            if (font) tf->setFontZ(dynamic_cast<Font*>(font->getThis()));
        }
    }
    if (DrawableBackground::hasStyle(Style::MultiStyled) && tfListe && styles)
    {
        auto style = styles->begin();
        for (auto tf = tfListe->begin(); tf; tf++, style++)
        {
            tf->setStyle(
                TextField::Style::Border, hasStyle(style, Style::FieldBorder));
            tf->setStyle(TextField::Style::Background,
                hasStyle(style, Style::FieldBackground));
            tf->setStyle(
                TextField::Style::BImage, hasStyle(style, Style::FieldBImage));
            tf->setStyle(
                TextField::Style::BAlpha, hasStyle(style, Style::FieldBAlpha));
            tf->setStyle(TextField::Style::Buffered,
                hasStyle(style, Style::FieldBuffer));
        }
    }
    rend = 1;
}

void SelectionList::addEntry(Text* txt) // adds an entry
{
    TextField* tf = new TextField();
    tf->setStyle(TextField::Style::Center | TextField::Style::Visible
                 | TextField::Style::Border);
    tf->setFontColor(0xFFFFFFFF);
    tf->setBorderWidth(1);
    tf->setBorderColor(0xFFFFFFFF);
    tf->setTextZ(txt);
    tf->setSize(0, 20);
    addEntryZ(tf);
    rend = 1;
}

void SelectionList::addEntry(const char* txt)
{
    Text* tx = new Text(txt);
    addEntry(tx);
    rend = 1;
}

void SelectionList::addEntryZ(TextField* tf)
{
    if (!tfListe) tfListe = new RCArray<TextField>();
    if (font && (!tf->zFont() || hasStyleNot(Style::MultiStyled)))
        tf->setFontZ(dynamic_cast<Font*>(font->getThis()));
    tfListe->add(tf);
    rend = 1;
}

void SelectionList::addEntry(
    int pos, Text* txt) // inserts an entry at position pos
{
    TextField* tf = new TextField();
    tf->setStyle(TextField::Style::Center | TextField::Style::Visible
                 | TextField::Style::Border);
    tf->setFontColor(0xFFFFFFFF);
    tf->setBorderWidth(1);
    tf->setBorderColor(0xFFFFFFFF);
    tf->setTextZ(txt);
    tf->setSize(0, 20);
    addEntryZ(pos, tf);
    rend = 1;
}

void SelectionList::addEntry(int pos, const char* txt)
{
    Text* tx = new Text(txt);
    addEntry(pos, tx);
    rend = 1;
}

void SelectionList::addEntryZ(int pos, TextField* tf)
{
    if (!tfListe) tfListe = new RCArray<TextField>();
    if (font && (!tf->zFont() || hasStyleNot(Style::MultiStyled)))
        tf->setFontZ(dynamic_cast<Font*>(font->getThis()));
    tfListe->add(tf, pos);
    rend = 1;
}

void SelectionList::setEntry(int pos, Text* txt) // changes the entry at pos
{
    TextField* tf = 0;
    if (tfListe) tf = tfListe->z(pos);
    if (!tf)
    {
        tf = new TextField();
        tf->setStyle(TextField::Style::Center | TextField::Style::Visible
                     | TextField::Style::Border);
        tf->setFontColor(0xFFFFFFFF);
        tf->setBorderColor(0xFFFFFFFF);
        tf->setBorderWidth(1);
        tf->setTextZ(txt);
        tf->setSize(0, 20);
        setEntryZ(pos, tf);
        rend = 1;
        return;
    }
    tf->setTextZ(txt);
    rend = 1;
}

void SelectionList::setEntry(int pos, const char* txt)
{
    Text* tx = new Text(txt);
    setEntry(pos, tx);
    rend = 1;
}

void SelectionList::setEntryZ(int pos, TextField* tf)
{
    if (!tfListe) tfListe = new RCArray<TextField>();
    if (font && (!tf->zFont() || hasStyleNot(Style::MultiStyled)))
        tf->setFontZ(dynamic_cast<Font*>(font->getThis()));
    tfListe->set(tf, pos);
    rend = 1;
}

void SelectionList::swapEntryPos(
    int vpos, int npos) // swaps entry vpos with entry npos
{
    if (tfListe)
    {
        tfListe->swap(vpos, npos);
        if (styles) styles->swap(vpos, npos);
        if (ahColorListe) ahColorListe->swap(vpos, npos);
        if (ahImageListe) ahImageListe->swap(vpos, npos);
        if (aBufferListe) aBufferListe->swap(vpos, npos);
        if (aBorderList) aBorderList->swap(vpos, npos);
        rend = 1;
    }
}

void Framework::SelectionList::setEntryPos(int vpos, int npos)
{
    if (tfListe)
    {
        tfListe->setPosition(vpos, npos);
        if (styles) styles->setPosition(vpos, npos);
        if (ahColorListe) ahColorListe->setPosition(vpos, npos);
        if (ahImageListe) ahImageListe->setPosition(vpos, npos);
        if (aBufferListe) aBufferListe->setPosition(vpos, npos);
        if (aBorderList) aBorderList->setPosition(vpos, npos);
        rend = 1;
    }
}

void SelectionList::removeEntry(int pos) // deletes entry at pos
{
    tfListe->remove(pos);
    rend = 1;
}

void SelectionList::setFontZ(Font* font) // sets the font for the entries
{
    if (this->font) this->font->release();
    this->font = font;
    rend = 1;
}

void SelectionList::setVScrollToEntry(int entry) // scrolls to entry
{
    if (vertikalScrollBar)
    {
        if (entry > tfListe->getLastIndex()) entry = tfListe->getLastIndex();
        int y = 0;
        for (int i = 0; i < entry; i++)
            y += tfListe->z(i) ? tfListe->z(i)->getHeight() : 0;
        vertikalScrollBar->scroll(y);
    }
}

void SelectionList::updateVScroll() // scrolls to cursor position or
                                    // down
{
    if (vertikalScrollBar)
    {
        int y = 0;
        for (TextField* tf : *tfListe)
            y += (TextField*)tf ? tf->getHeight() : 0;
        vertikalScrollBar->update(y,
            gr.y
                - ((border
                       && DrawableBackground::hasStyle(
                           TextField::Style::Border))
                        ? border->getRWidth()
                        : 0));
    }
}

void SelectionList::setSelectionBorderZ(
    Border* border) // sets a pointer to the selection border (only without
                    // MultiStyled)
{
    if (aBorder) aBorder->release();
    aBorder = border;
    rend = 1;
}

void SelectionList::setSelectionBorderWidth(
    int br) // sets the width of the selection border (only without MultiStyled)
{
    if (!aBorder) aBorder = new LBorder();
    aBorder->setBorderWidth(br);
    rend = 1;
}

void SelectionList::setSelectionBorderColor(
    int fc) // sets the color of the selection border (only without MultiStyled)
{
    if (!aBorder) aBorder = new LBorder();
    aBorder->setColor(fc);
    rend = 1;
}

void SelectionList::setSelectionAFZ(
    AlphaField* buffer) // sets a pointer to the selection
                        // AlphaField (only without MultiStyled)
{
    if (aBuffer) aBuffer->release();
    aBuffer = buffer;
    rend = 1;
}

void SelectionList::setSelectionAFStrength(
    int st) // sets the strength of the selection background buffer (only
            // without MultiStyled)
{
    if (!aBuffer) aBuffer = new AlphaField();
    aBuffer->setStrength(st);
    rend = 1;
}

void SelectionList::setSelectionAFColor(
    int fc) // sets the color of the selection background buffer (only without
            // MultiStyled)
{
    if (!aBuffer) aBuffer = new AlphaField();
    aBuffer->setColor(fc);
    rend = 1;
}

void SelectionList::setSelectionBImage(Image*
        bild) // sets the selection background image (only without MultiStyled)
{
    if (!ahImage) ahImage = new Image();
    ahImage->newImage(bild->getWidth(), bild->getHeight(), 0);
    int* buff1 = ahImage->getBuffer();
    int* buff2 = bild->getBuffer();
    for (int i = 0; i < bild->getWidth() * bild->getHeight(); ++i)
        buff1[i] = buff2[i];
    bild->release();
    rend = 1;
}

void SelectionList::setSelectionBColor(
    int f) // sets the selection
           // background color (only without MultiStyled)
{
    ahColor = f;
    rend = 1;
}

void SelectionList::setSelectionBImageZ(Image*
        b) // sets a pointer to the background image (only without MultiStyled)
{
    if (ahImage) ahImage->release();
    ahImage = b;
    rend = 1;
}

void SelectionList::setSelectionBorderZ(int pos,
    Border* border) // sets a pointer to the selection border (only with
                    // MultiStyled)
{
    if (!aBorderList) aBorderList = new RCArray<Border>();
    aBorderList->set(border, pos);
    rend = 1;
}

void SelectionList::setSelectionBorderWidth(int pos,
    int br) // sets the width of the selection border (only with MultiStyled)
{
    if (!aBorderList) aBorderList = new RCArray<Border>();
    if (!aBorderList->z(pos)) aBorderList->set(new LBorder(), pos);
    aBorderList->z(pos)->setBorderWidth(br);
    rend = 1;
}

void SelectionList::setSelectionBorderColor(int pos,
    int fc) // sets the color of the selection border (only with MultiStyled)
{
    if (!aBorderList) aBorderList = new RCArray<Border>();
    if (!aBorderList->z(pos)) aBorderList->set(new LBorder(), pos);
    aBorderList->z(pos)->setColor(fc);
    rend = 1;
}

void SelectionList::setSelectionAFZ(int pos,
    AlphaField* buffer) // sets a pointer to the selection AlphaField (only with
                        // MultiStyled)
{
    if (!aBufferListe) aBufferListe = new RCArray<AlphaField>();
    aBufferListe->set(buffer, pos);
    rend = 1;
}

void SelectionList::setSelectionAFStrength(
    int pos, int st) // sets the strength of the selection background buffer
                     // (only with MultiStyled)
{
    if (!aBufferListe) aBufferListe = new RCArray<AlphaField>();
    if (!aBufferListe->z(pos)) aBufferListe->set(new AlphaField(), pos);
    aBufferListe->z(pos)->setStrength(st);
    rend = 1;
}

void SelectionList::setSelectionAFColor(
    int pos, int fc) // sets the color of the selection background buffer
                     // (only with MultiStyled)
{
    if (!aBufferListe) aBufferListe = new RCArray<AlphaField>();
    if (!aBufferListe->z(pos)) aBufferListe->set(new AlphaField(), pos);
    aBufferListe->z(pos)->setColor(fc);
    rend = 1;
}

void SelectionList::setSelectionBImage(int pos,
    Image* bild) // sets the selection background image (only with MultiStyled)
{
    if (ahImageListe) ahImageListe = new RCArray<Image>();
    if (!ahImageListe->z(pos)) ahImageListe->set(new Image(), pos);
    ahImageListe->z(pos)->newImage(bild->getWidth(), bild->getHeight(), 0);
    int* buff1 = ahImageListe->z(pos)->getBuffer();
    int* buff2 = bild->getBuffer();
    for (int i = 0; i < bild->getWidth() * bild->getHeight(); ++i)
        buff1[i] = buff2[i];
    bild->release();
    rend = 1;
}

void SelectionList::setSelectionBColor(
    int pos, int f) // sets the selection background color
                    // (only with MultiStyled)
{
    if (ahColorListe) ahColorListe = new Array<int>();
    ahColorListe->set(f, pos);
    rend = 1;
}

void SelectionList::setSelectionBImageZ(int pos,
    Image* b) // sets a pointer to the background image (only with MultiStyled)
{
    if (ahImageListe) ahImageListe = new RCArray<Image>();
    ahImageListe->set(b, pos);
    rend = 1;
}

void SelectionList::setMsStyle(int pos,
    __int64 style) // sets the style of the entry (only with MultiStyled)
{
    if (!styles) styles = new Array<__int64>();
    styles->set(style, pos);
    rend = 1;
}

void SelectionList::setMsStyle(int pos, __int64 style, bool add_remove)
{
    if (!styles) styles = new Array<__int64>();
    if (add_remove)
        styles->set(styles->get(pos) | style, pos);
    else
        styles->set(styles->get(pos) & ~style, pos);
    rend = 1;
}

void SelectionList::addMsStyle(int pos, __int64 style)
{
    if (!styles) styles = new Array<__int64>();
    styles->set(styles->get(pos) | style, pos);
    rend = 1;
}

void SelectionList::removeMsStyle(int pos, __int64 style)
{
    if (!styles) styles = new Array<__int64>();
    styles->set(styles->get(pos) & ~style, pos);
    rend = 1;
}

void SelectionList::doKeyboardEvent(KeyboardEvent& te)
{
    bool ntakc = !te.processed;
    if (hasStyleNot(Style::Focus) || !tak || te.processed) return;
    getThis();
    if (tak(takParam, this, te))
    {
        if (te.id == TE_Press)
        {
            if (hasStyleNot(Style::MultiSelect))
            {
                switch (te.virtualKey)
                {
                case T_Unten:
                    ++selection;
                    if (selection > tfListe->getEntryCount())
                        selection = tfListe->getEntryCount();
                    rend = 1;
                    break;
                case T_Oben:
                    --selection;
                    if (selection < -1) selection = -1;
                    rend = 1;
                    break;
                }
            }
            else
            {
                switch (te.virtualKey)
                {
                case T_Unten:
                    deselect();
                    ++selection;
                    if (selection > tfListe->getEntryCount())
                        selection = tfListe->getEntryCount();
                    if (selection >= 0) addMsStyle(selection, Style::Selected);
                    rend = 1;
                    break;
                case T_Oben:
                    deselect();
                    --selection;
                    if (selection < -1) selection = -1;
                    if (selection >= 0) addMsStyle(selection, Style::Selected);
                    rend = 1;
                    break;
                }
            }
        }
        te.processed = 1;
    }
    if (ntakc && te.processed && nTak) te.processed = nTak(ntakParam, this, te);
    release();
}

void SelectionList::render(Image& zRObj) // draws to zRObj
{
    if (!DrawableBackground::hasStyle(Style::Visible)) return;
    removeStyle(Style::HScroll);
    DrawableBackground::render(zRObj);
    rwLock.lockRead();
    if (!zRObj.setDrawOptions(innenPosition, innenSize))
    {
        rwLock.unlockRead();
        return;
    }
    int rbr = 0;
    if (border && DrawableBackground::hasStyle(Style::Border))
        rbr = border->getRWidth();
    if (tfListe)
    {
        int maxHeight = 0;
        int dx = 0, dy = 0;
        if (vertikalScrollBar && DrawableBackground::hasStyle(Style::VScroll))
            dy -= vertikalScrollBar->getScroll();
        int mdy = innenSize.y + rbr;
        auto style = styles ? styles->begin() : Array<__int64>().begin();
        int i = 0;
        for (auto tf = tfListe->begin(); tf; tf++, style++, i++)
        {
            if (dy + tf->getHeight() > mdy
                && !(vertikalScrollBar
                     && DrawableBackground::hasStyle(Style::VScroll)))
                break;
            tf->setPosition(dx, dy);
            tf->setSize(innenSize.x, tf->getHeight());
            maxHeight += tf->getHeight();
            bool selected = 0;
            if (DrawableBackground::hasStyle(Style::MultiSelect) && styles)
                selected = hasStyle(style, Style::Selected);
            else
                selected = selection == i;
            AlphaField* tmpBuffer = 0;
            bool tmpB = 0;
            int tmpHColor = 0;
            bool tmpH = 0;
            Image* tmpHImage = 0;
            bool tmpHB = 0;
            bool tmpHAlpha = 0;
            Border* tmpBorder = 0;
            bool tmpR = 0;
            if (selected)
            {
                if (hasStyleNot(Style::MultiStyled) || !styles)
                {
                    if (DrawableBackground::hasStyle(Style::SelectionBuffer)
                        && aBuffer)
                    {
                        tmpBuffer = tf->getAlphaField();
                        tf->setAlphaFieldZ(
                            dynamic_cast<AlphaField*>(aBuffer->getThis()));
                        tmpB = tf->hasStyle(TextField::Style::Buffered);
                        tf->setStyle(TextField::Style::Buffered,
                            DrawableBackground::hasStyle(
                                Style::SelectionBuffer));
                    }
                    if (DrawableBackground::hasStyle(
                            Style::SelectionBackground))
                    {
                        tmpH = tf->hasStyle(TextField::Style::Background);
                        tmpHColor = tf->getBackgroundColor();
                        tf->setBackgroundColor(ahColor);
                        tf->setStyle(TextField::Style::Background,
                            DrawableBackground::hasStyle(Style::Background));
                        if (DrawableBackground::hasStyle(Style::SelectionBImage)
                            && ahImage)
                        {
                            tmpHImage = tf->getBackgroundImage();
                            tf->setBackgroundImageZ(
                                dynamic_cast<Image*>(ahImage->getThis()));
                            tmpHB = tf->hasStyle(TextField::Style::BImage);
                            tf->setStyle(TextField::Style::BImage,
                                DrawableBackground::hasStyle(Style::BImage));
                        }
                        if (DrawableBackground::hasStyle(
                                Style::SelectionBAlpha))
                        {
                            tmpHAlpha = tf->hasStyle(TextField::Style::BAlpha);
                            tf->setStyle(TextField::Style::BAlpha,
                                DrawableBackground::hasStyle(
                                    Style::SelectionBAlpha));
                        }
                    }
                    if (DrawableBackground::hasStyle(Style::SelectionBorder)
                        && aBorder)
                    {
                        tmpBorder = tf->getBorder();
                        tf->setBorderZ(
                            dynamic_cast<Border*>(aBorder->getThis()));
                        tmpR = tf->hasStyle(TextField::Style::Border);
                        tf->setStyle(TextField::Style::Border,
                            DrawableBackground::hasStyle(
                                Style::SelectionBorder));
                    }
                }
                else
                {
                    if (hasStyle(style, Style::SelectionBuffer) && aBufferListe)
                    {
                        tmpBuffer = tf->getAlphaField();
                        tf->setAlphaFieldZ(aBufferListe->get(i));
                        tmpB = tf->hasStyle(TextField::Style::Buffered);
                        tf->setStyle(TextField::Style::Buffered,
                            hasStyle(style, Style::SelectionBuffer));
                    }
                    if (hasStyle(style, Style::SelectionBackground))
                    {
                        tmpH = tf->hasStyle(Style::Background);
                        tf->setStyle(TextField::Style::Background,
                            hasStyle(style, Style::SelectionBackground));
                        if (ahColorListe && ahColorListe->has(i))
                        {
                            tmpHColor = tf->getBackgroundColor();
                            tf->setBackgroundColor(ahColorListe->get(i));
                        }
                        if (hasStyle(style, Style::SelectionBImage)
                            && ahImageListe)
                        {
                            tmpHImage = tf->getBackgroundImage();
                            tf->setBackgroundImageZ(ahImageListe->get(i));
                            tmpHB = tf->hasStyle(TextField::Style::BImage);
                            tf->setStyle(TextField::Style::BImage,
                                hasStyle(style, Style::BImage));
                        }
                        if (hasStyle(style, Style::SelectionBAlpha))
                        {
                            tmpHAlpha = tf->hasStyle(TextField::Style::BAlpha);
                            tf->setStyle(TextField::Style::BAlpha,
                                hasStyle(style, Style::SelectionBAlpha));
                        }
                    }
                    if (hasStyle(style, Style::SelectionBorder) && aBorderList)
                    {
                        tmpBorder = tf->getBorder();
                        tf->setBorderZ(aBorderList->get(i));
                        tmpR = tf->hasStyle(TextField::Style::Border);
                        tf->setStyle(TextField::Style::Border,
                            hasStyle(style, Style::SelectionBorder));
                    }
                }
            }
            tf->render(zRObj);
            if (selected)
            {
                if (hasStyleNot(Style::MultiStyled) || !styles)
                {
                    if (DrawableBackground::hasStyle(Style::SelectionBuffer))
                    {
                        tf->setAlphaFieldZ(tmpBuffer);
                        tf->setStyle(TextField::Style::Buffered, tmpB);
                    }
                    if (DrawableBackground::hasStyle(
                            Style::SelectionBackground))
                    {
                        tf->setBackgroundColor(tmpHColor);
                        tf->setStyle(TextField::Style::Background, tmpH);
                        if (DrawableBackground::hasStyle(
                                Style::SelectionBImage))
                        {
                            tf->setBackgroundImageZ(tmpHImage);
                            tf->setStyle(TextField::Style::BImage, tmpHB);
                        }
                        if (DrawableBackground::hasStyle(
                                Style::SelectionBAlpha))
                            tf->setStyle(TextField::Style::BAlpha, tmpHAlpha);
                    }
                    if (DrawableBackground::hasStyle(Style::SelectionBorder))
                    {
                        tf->setBorderZ(tmpBorder);
                        tf->setStyle(TextField::Style::Border, tmpR);
                    }
                }
                else
                {
                    if (hasMsStyle(i, Style::SelectionBuffer) && aBufferListe)
                    {
                        tf->setAlphaFieldZ(tmpBuffer);
                        tf->setStyle(TextField::Style::Buffered, tmpB);
                    }
                    if (hasMsStyle(i, Style::SelectionBackground))
                    {
                        tf->setStyle(TextField::Style::Background, tmpH);
                        if (ahColorListe && ahColorListe->has(i))
                            tf->setBackgroundColor(tmpHColor);
                        if (hasMsStyle(i, Style::SelectionBImage)
                            && ahImageListe)
                        {
                            tf->setBackgroundImageZ(tmpHImage);
                            tf->setStyle(TextField::Style::BImage, tmpHB);
                        }
                        if (hasMsStyle(i, Style::SelectionBAlpha))
                            tf->setStyle(TextField::Style::BAlpha, tmpHAlpha);
                    }
                    if (hasMsStyle(i, Style::SelectionBorder) && aBorderList)
                    {
                        tf->setBorderZ(tmpBorder);
                        tf->setStyle(TextField::Style::Border, tmpR);
                    }
                }
            }
            dy += tf->getHeight();
        }
        if (vertikalScrollBar)
            vertikalScrollBar->getScrollData()->max = maxHeight;
    }
    zRObj.releaseDrawOptions();
    rwLock.unlockRead();
}

int SelectionList::getClickEntry(int my)
{
    if (!tfListe) return -1;
    int y = 0;
    if (DrawableBackground::hasStyle(Style::VScroll) && vertikalScrollBar)
        y -= vertikalScrollBar->getScroll();
    int i = 0;
    for (auto tf = tfListe->begin(); tf; tf++, i++)
    {
        y += tf->getHeight();
        if (y > my) return i;
    }
    return -1;
}

void SelectionList::setSelection(int sel) // sets the selection
{
    if (hasStyleNot(Style::MultiSelect))
        selection = sel;
    else if (styles)
    {
        for (int i = 0; i < styles->getEntryCount(); ++i)
            removeMsStyle(i, Style::Selected);
        addMsStyle(sel, Style::Selected);
    }
}

void SelectionList::deselect()
{
    if (hasStyleNot(Style::MultiSelect))
        selection = -1;
    else if (styles)
    {
        for (int i = 0; i < styles->getEntryCount(); ++i)
            removeMsStyle(i, Style::Selected);
    }
}

// constant
int SelectionList::getEntryCount() const // returns the number of entries
{
    return tfListe ? tfListe->getEntryCount() : 0;
}

int SelectionList::getSelection() const // returns the first selected entry
{
    return selection;
}

int SelectionList::getEntryPos(
    Text* entryText) // returns the position of the entry with the
                     // corresponding text
{
    int i = 0;
    for (auto tf = tfListe->begin(); tf; tf++, i++)
    {
        if (tf->zText()->isEqual(entryText->getText()))
        {
            entryText->release();
            return i;
        }
    }
    return -1;
}

TextField* SelectionList::getEntry(
    int pos) const // returns the entry at position pos
{
    if (!tfListe) return 0;
    TextField* ret = (TextField*)tfListe->get(pos);
    if (ret) return dynamic_cast<TextField*>(ret->getThis());
    return 0;
}

TextField* SelectionList::zEntry(int pos) const
{
    if (!tfListe) return 0;
    return (TextField*)tfListe->z(pos);
}

Border* SelectionList::getSelectionBorder()
    const // returns the selection border (without MultiStyled)
{
    if (aBorder) return dynamic_cast<Border*>(aBorder->getThis());
    return 0;
}

Border* SelectionList::zSelectionBorder() const
{
    return aBorder;
}

int SelectionList::getSelectionBColor()
    const // returns the selection background color (without MultiStyled)
{
    return ahColor;
}

Image* SelectionList::getSelectionBImage()
    const // returns the selection background image (without MultiStyled)
{
    if (ahImage) return dynamic_cast<Image*>(ahImage->getThis());
    return 0;
}

Image* SelectionList::zSelectionBImage() const
{
    return ahImage;
}

AlphaField* SelectionList::getSelectionBuffer()
    const // returns the selection buffer (without MultiStyled)
{
    if (aBuffer) return dynamic_cast<AlphaField*>(aBuffer->getThis());
    return 0;
}

AlphaField* SelectionList::zSelectionBuffer() const
{
    return aBuffer;
}

Border* SelectionList::getSelectionBorder(
    int pos) const // returns the selection border (with MultiStyled)
{
    Border* ret = 0;
    if (aBorderList) ret = (Border*)aBorderList->get(pos);
    if (ret) return dynamic_cast<Border*>(ret->getThis());
    return 0;
}

Border* SelectionList::zSelectionBorder(int pos) const
{
    Border* ret = 0;
    if (aBorderList) ret = (Border*)aBorderList->z(pos);
    return ret;
}

int SelectionList::getSelectionBColor(
    int pos) const // returns the selection background color (with MultiStyled)
{
    if (ahColorListe && ahColorListe->has(pos)) return ahColorListe->get(pos);
    return 0;
}

Image* SelectionList::getSelectionBImage(
    int pos) const // returns the selection background image (with MultiStyled)
{
    Image* ret = 0;
    if (ahImageListe) ret = (Image*)ahImageListe->get(pos);
    if (ret) return dynamic_cast<Image*>(ret->getThis());
    return 0;
}

Image* SelectionList::zSelectionBImage(int pos) const
{
    Image* ret = 0;
    if (ahImageListe) ret = (Image*)ahImageListe->z(pos);
    return ret;
}

AlphaField* SelectionList::getSelectionBuffer(
    int pos) const // returns the selection buffer (with MultiStyled)
{
    AlphaField* ret = 0;
    if (aBufferListe) ret = (AlphaField*)aBufferListe->get(pos);
    if (ret) return dynamic_cast<AlphaField*>(ret->getThis());
    return 0;
}

AlphaField* SelectionList::zSelectionBuffer(int pos) const
{
    AlphaField* ret = 0;
    if (aBufferListe) ret = (AlphaField*)aBufferListe->z(pos);
    return ret;
}

bool SelectionList::hasMsStyle(int pos,
    __int64 style) const // checks if style is present (with MultiStyled)
{
    __int64 st = 0;
    if (styles) st = styles->get(pos);
    return (st | style) == st;
}

bool SelectionList::hasMsStyleNot(int pos,
    __int64 style) const // checks if style is not present (with MultiStyled)
{
    __int64 st = 0;
    if (styles) st = styles->get(pos);
    return (st | style) != st;
}

//! Constructor
DrawableList::DrawableList()
    : DrawableBackground()
{
    entrySeperatorSize = 1;
    entrySeperatorColor = 0xFFFFFFFF;
    setBorderWidth(1);
    setBorderColor(0xFFFFFFFF);
    setBackgroundColor(0xFF000000);
}

//! Destructor
DrawableList::~DrawableList() {}

//! Processes mouse messages
//! \param me The event triggered by the mouse input
void DrawableList::doMouseEvent(MouseEvent& me, bool userRet)
{
    if (DrawableBackground::hasStyle(Style::VScroll) && vertikalScrollBar)
    {
        int rbr = 0;
        if (border && DrawableBackground::hasStyle(Style::Border))
            rbr = border->getRWidth();
        if (((me.mx > gr.x - 15 - rbr) || me.id == ME_UScroll
                || me.id == ME_DScroll)
            && me.id != ME_Enter && me.id != ME_Leaves)
        {
            vertikalScrollBar->doMouseMessage(
                gr.x - rbr - 15, rbr, 15, gr.y - rbr * 2, me);
            me.processed = 1;
        }
        me.my += vertikalScrollBar->getScroll();
    }
    me.my -= (border && DrawableBackground::hasStyle(TextField::Style::Border))
               ? border->getRWidth() * 2
               : 0;
    me.mx -= (border && DrawableBackground::hasStyle(TextField::Style::Border))
               ? border->getRWidth() * 2
               : 0;
    int ySum = 0;
    int index = 0;
    for (Drawable* entry : list)
    {
        entry->doPublicMouseEvent(me);
        ySum += entry->getHeight();
        me.my -= entry->getHeight();
        if (index < list.getLastIndex())
        {
            ySum += DrawableBackground::hasStyle(
                        DrawableList::Style::EntrySeperator)
                      ? entrySeperatorSize
                      : 0;
            me.my -= DrawableBackground::hasStyle(
                         DrawableList::Style::EntrySeperator)
                       ? entrySeperatorSize
                       : 0;
        }
        index++;
    }
    me.my
        += ySum
                 + (border
                     && DrawableBackground::hasStyle(TextField::Style::Border))
             ? border->getRWidth() * 2
             : 0;
    me.mx += (border && DrawableBackground::hasStyle(TextField::Style::Border))
               ? border->getRWidth() * 2
               : 0;
    if (DrawableBackground::hasStyle(Style::VScroll) && vertikalScrollBar)
        me.my -= vertikalScrollBar->getScroll();
}

//! Adds an entry
//! \param entry The drawing to add
void DrawableList::addEntry(Drawable* entry)
{
    rend = 1;
    list.add(entry);
}

//! Changes an entry
//! \param pos The index of the entry
//! \param entry The new drawing
void DrawableList::setEntry(int pos, Drawable* entry)
{
    rend = 1;
    list.set(entry, pos);
}

//! Swaps the positions of two entries
//! \param vpos The index of the first entry
//! \param npos The index of the second entry
void DrawableList::swapEntryPos(int vPos, int nPos)
{
    rend = 1;
    list.swap(vPos, nPos);
}

void Framework::DrawableList::setEntryPos(int vpos, int npos)
{
    list.setPosition(vpos, npos);
}

//! Deletes an entry
//! pos: The index of the entry
void DrawableList::removeEntry(int pos)
{
    rend = 1;
    list.remove(pos);
}

//! Scrolls to a specific entry
//! \param entry The index of the entry
void DrawableList::setVScrollToEntry(int entry)
{
    if (vertikalScrollBar)
    {
        if (entry > list.getLastIndex()) entry = list.getLastIndex();
        int y = 0;
        int index = 0;
        for (Drawable* entry : list)
        {
            y += entry->getHeight();
            if (index < list.getLastIndex())
                y += DrawableBackground::hasStyle(
                         DrawableList::Style::EntrySeperator)
                       ? entrySeperatorSize
                       : 0;
            index++;
        }
        vertikalScrollBar->scroll(y);
    }
}

//! Updates the maximum scroll height by adding the heights of all entries
void DrawableList::updateVScroll()
{
    if (vertikalScrollBar)
    {
        int y = 0;
        int index = 0;
        for (Drawable* entry : list)
        {
            y += entry->getHeight();
            if (index < list.getLastIndex())
                y += DrawableBackground::hasStyle(
                         DrawableList::Style::EntrySeperator)
                       ? entrySeperatorSize
                       : 0;
            index++;
        }
        vertikalScrollBar->update(y,
            gr.y
                - ((border
                       && DrawableBackground::hasStyle(
                           TextField::Style::Border))
                        ? border->getRWidth() * 2
                        : 0));
    }
}

//! sets the size of the entry seperator
void DrawableList::setEntrySeperatorSize(int size)
{
    entrySeperatorSize = size;
}

//! sets the color of the entry seperator
void DrawableList::setEntrySeperatorColor(int color)
{
    entrySeperatorColor = color;
}

//! Processes a keyboard event. Called automatically by the framework
//! \param te The event
void DrawableList::doKeyboardEvent(KeyboardEvent& te)
{
    for (Drawable* entry : list)
        entry->doKeyboardEvent(te);
}

//! Updates the drawing
//! \param tickVal The elapsed time in seconds since the last call of this
//! function \return 1 if the drawing has changed since the last call
bool DrawableList::tick(double tickVal)
{
    bool ret = DrawableBackground::tick(tickVal);
    for (Drawable* entry : list)
        ret |= entry->tick(tickVal);
    return ret;
}

//! Draws the object to zRObj if it is visible
//! \param zRObj The image to draw into
void DrawableList::render(Image& rObj)
{
    DrawableBackground::render(rObj);
    int index = 0;
    int rbr = border && DrawableBackground::hasStyle(TextField::Style::Border)
                ? border->getRWidth()
                : 0;
    bool vs = vertikalScrollBar && hasStyle(Style::VScroll);
    if (rObj.setDrawOptions(pos + Point(rbr, rbr),
            gr - Point(rbr, rbr) * 2 - Point(vs ? 15 : 0, 0)))
    {
        if (vs) rObj.addScrollOffset(0, vertikalScrollBar->getScroll());
        for (Drawable* entry : list)
        {
            entry->setWidth(gr.x - rbr * 2 - (vs ? 15 : 0));
            entry->render(rObj);
            rObj.addScrollOffset(0, -entry->getHeight());
            if (index < list.getLastIndex()
                && DrawableBackground::hasStyle(
                    DrawableList::Style::EntrySeperator))
            {
                for (int i = 0; i < entrySeperatorSize; i++)
                {
                    rObj.drawLineHAlpha(
                        0, 0, gr.x - rbr - (vs ? 15 : 0), entrySeperatorColor);
                    rObj.addScrollOffset(0, -1);
                }
            }
            index++;
        }
        rObj.releaseDrawOptions();
    }
}

//! Returns the index of an entry the mouse points to
//! \param my The position of the mouse on the Y axis relative to the top
//! edge of the list
int DrawableList::getClickEntry(int my)
{
    if (my < 0) return -1;
    int index = 0;
    int y = 0;
    for (Drawable* entry : list)
    {
        if (my < y) return index;
        y += entry->getHeight();
        if (index < list.getLastIndex())
            y += DrawableBackground::hasStyle(
                     DrawableList::Style::EntrySeperator)
                   ? entrySeperatorSize
                   : 0;
        index++;
    }
    return -1;
}

//! Returns the number of entries
int DrawableList::getEntryCount() const
{
    return list.getEntryCount();
}

//! Returns the index of an entry
//! \param zEntry The drawing
int DrawableList::getEntryPos(Drawable* zEntry)
{
    int index = 0;
    for (Drawable* entry : list)
    {
        if (zEntry == entry) return index;
        index++;
    }
    return -1;
}

//! Returns an entry
//! \param pos The index of the entry
Drawable* DrawableList::getEntry(int pos) const
{
    return list.get(pos);
}

//! Returns an entry without increased reference counter
//! \param pos The index of the entry
Drawable* DrawableList::zEntry(int pos) const
{
    return list.get(pos);
}

//! Returns the needed height
int DrawableList::getNeededHeight() const
{
    int y = (border && DrawableBackground::hasStyle(TextField::Style::Border))
              ? border->getRWidth() * 2
              : 0;
    int index = 0;
    for (Drawable* entry : list)
    {
        y += entry->getHeight();
        if (index < list.getLastIndex())
            y += DrawableBackground::hasStyle(
                     DrawableList::Style::EntrySeperator)
                   ? entrySeperatorSize
                   : 0;
        index++;
    }
    return y;
}

//! returns the size of the entry seperator
int DrawableList::getEntrySeperatorSize() const
{
    return entrySeperatorSize;
}

//! returns the color of the entry seperator
int DrawableList::getEntrySeperatorColor() const
{
    return entrySeperatorColor;
}