#include "Drawing.h"

#include "AlphaField.h"
#include "Border.h"
#include "Font.h"
#include "Globals.h"
#include "Image.h"
#include "KeyboardEvent.h"
#include "MouseEvent.h"
#include "Screen.h"
#include "Scroll.h"
#include "Text.h"
#include "TextField.h"
#include "ToolTip.h"
#include "UIInitialization.h"
#ifdef WIN32
#    include <Windows.h>
#endif

using namespace Framework;

// Contents of the Drawable class from Drawing.h
// Constructor
Drawable::Drawable()
    : ReferenceCounter(),
      pos(0, 0),
      gr(0, 0),
      makParam(0),
      takParam(0),
      mak(0),
      tak(0),
      nmakParam(0),
      ntakParam(0),
      nMak(0),
      nTak(0),
      mouseIn(0),
      toolTip(0),
      style(0),
      rend(0),
      onNeedToolTip(0),
      toolTipRequested(0)
{}

// Destructor
Drawable::~Drawable()
{
    if (toolTip) toolTip->release();
}

void Drawable::doMouseEvent(MouseEvent& me, bool userRet)
{
    me.processed = userRet;
}

// non-constant
void Drawable::setRender()
{
    rend = 1;
}

void Drawable::setToolTipText(const char* txt, Screen* zScreen, Font* zFont)
{
    if (!txt)
        toolTip = (ToolTip*)toolTip->release();
    else
    {
        if (!toolTip)
        {
            toolTip = new ToolTip(zScreen);
            toolTip->addStyle(DrawableBackground::Style::Background
                              | DrawableBackground::Style::BAlpha
                              | DrawableBackground::Style::Border
                              | DrawableBackground::Style::Visible);
            toolTip->setBackgroundColor(0xA0000000);
            toolTip->setBorderColor(0xFFFFFFFF);
            toolTip->setBorderWidth(1);
            if (mouseIn && toolTip) toolTip->setMouseIn(1);
        }
        UIInit init = defaultUI(zFont, zScreen);
        TextField* t = init.createTextField(init.initParam);
        t->setText(txt);
        t->setSize(t->zTextRenderer()->getTextWidth(txt),
            t->zTextRenderer()->getTextHeight(txt));
        toolTip->addMember(t);
    }
    toolTipRequested = 0;
}

// sets a function that creates a tooltip on first use
// if one does not exist yet
//  initToolTip: the function
void Drawable::setNeedToolTipEvent(
    std::function<bool(Drawable*, Point localPos)> onNeedToolTip)
{
    this->onNeedToolTip = onNeedToolTip;
}

// sets the tooltip
// tt: the tooltip
void Drawable::setToolTipZ(ToolTip* tt)
{
    if (toolTip) toolTip->release();
    toolTip = tt;
    if (mouseIn && toolTip) toolTip->setMouseIn(1);
    toolTipRequested = 0;
}

Lock& Drawable::readLock()
{
    return rwLock.getReadLock();
}

Lock& Drawable::writeLock()
{
    return rwLock.getWriteLock();
}

void Drawable::setMouseEventParameter(void* p) // sets the mouse event parameter
{
    makParam = p;
}

void Drawable::setKeyboardEventParameter(
    void* p) // sets the keyboard event parameter
{
    takParam = p;
}

void Drawable::setMouseEvent(MouseAction ak) // sets the mouse event
{
    mak = ak;
}

void Framework::Drawable::addMouseEvent(MouseAction ak)
{
    if (!mak)
    {
        mak = ak;
    }
    else
    {
        MouseAction old = mak;
        mak = [old, ak](void* p, void* o, MouseEvent me) {
            return old(p, o, me) && ak(p, o, me);
        };
    }
}

void Drawable::setKeyboardEvent(KeyboardAction ak) // sets the keyboard event
{
    tak = ak;
}

void Framework::Drawable::addKeyboardEvent(KeyboardAction ak)
{
    if (!tak)
    {
        tak = ak;
    }
    else
    {
        KeyboardAction old = tak;
        tak = [old, ak](void* p, void* o, KeyboardEvent te) {
            return old(p, o, te) && ak(p, o, te);
        };
    }
}

void Drawable::setPostMouseEventParameter(
    void* p) // sets the mouse event parameter
{
    nmakParam = p;
}

void Drawable::setPostKeyboardEventParameter(
    void* p) // sets the keyboard event parameter
{
    ntakParam = p;
}

void Drawable::setPostMouseEvent(MouseAction ak) // sets the mouse event
{
    nMak = ak;
}

void Drawable::setPostKeyboardEvent(
    KeyboardAction ak) // sets the keyboard event
{
    nTak = ak;
}

void Drawable::doPublicMouseEvent(MouseEvent& me) // calls Mak
{
    rwLock.lockRead();
    bool inside = isPointInside(me.mx, me.my);
    if (!me.insideParent || me.processed || !inside)
    {
        if (mouseIn)
        {
            mouseIn = 0;
            if (toolTip) toolTip->setMouseIn(0);
            MouseEvent me2;
            me2.id = ME_Leaves;
            me2.mx = me.mx - pos.x;
            me2.my = me.my - pos.y;
            me2.processed = 0;
            me2.insideParent = me.insideParent;
            bool userRet = mak && mak(makParam, this, me2);
            doMouseEvent(me2, userRet);
        }
    }
    if (!inside && me.id == ME_PLeft) removeStyle(Style::Focus);
    if ((me.processed && hasStyleNot(Style::MEIgnoreProcessed))
        || (!inside && hasStyleNot(Style::MEIgnoreInside))
        || (hasStyleNot(Style::Visible) && hasStyleNot(Style::MEIgnoreVisible)))
    {
        rwLock.unlockRead();
        return;
    }
    if (inside && me.id == ME_PLeft) addStyle(Style::Focus);
    if (me.insideParent && !mouseIn && me.id != ME_Leaves && inside
        && !me.processed && hasStyle(Style::Visible))
    {
        mouseIn = 1;
        if (toolTip)
            toolTip->setMouseIn(1);
        else if (onNeedToolTip && !toolTipRequested)
        {
            toolTipRequested
                = onNeedToolTip(this, Point(me.mx - pos.x, me.my - pos.y));
        }
        MouseEvent me2;
        me2.id = ME_Enter;
        me2.mx = me.mx - pos.x;
        me2.my = me.my - pos.y;
        me2.processed = 0;
        me2.insideParent = 1;
        bool userRet = mak && mak(makParam, this, me2);
        doMouseEvent(me2, userRet);
    }
    else if (me.insideParent && mouseIn && me.id != ME_Leaves && inside
             && !me.processed && hasStyle(Style::Visible) && !toolTip
             && onNeedToolTip && !toolTipRequested)
    {
        toolTipRequested
            = onNeedToolTip(this, Point(me.mx - pos.x, me.my - pos.y));
    }
    Point old = Point(me.mx, me.my);
    me.mx -= pos.x, me.my -= pos.y;
    if (me.insideParent || hasStyle(Style::MEIgnoreParentInside))
    {
        bool userRet = hasStyle(Style::Allowed)
                    && (me.processed || !me.insideParent
                        || (inside && mak && mak(makParam, this, me)));
        bool vera = me.processed;
        doMouseEvent(me, userRet);
        if (nMak && me.processed && !vera && hasStyle(Style::Allowed)
            && me.insideParent && inside)
            me.processed = nMak(nmakParam, this, me);
    }
    me.mx = old.x, me.my = old.y;
    rwLock.unlockRead();
}

void Drawable::doKeyboardEvent(KeyboardEvent& te) // calls Tak
{
    if (te.processed) return;
    if (tak) te.processed |= tak(takParam, this, te);
    if (nTak && te.processed) te.processed = nTak(ntakParam, this, te);
}

void Drawable::setPosition(const Point& pos) // sets the position
{
    rwLock.lockWrite();
    if (this->pos != pos) rend = 1;
    this->pos = pos;
    rwLock.unlockWrite();
}

void Drawable::setX(int xPos)
{
    rwLock.lockWrite();
    if (pos.x != xPos)
    {
        rend = 1;
        pos.x = xPos;
    }
    rwLock.unlockWrite();
}

void Drawable::setY(int yPos)
{
    rwLock.lockWrite();
    if (pos.y != yPos)
    {
        rend = 1;
        pos.y = yPos;
    }
    rwLock.unlockWrite();
}

void Drawable::setSize(const Point& gr) // sets the size
{
    rwLock.lockWrite();
    if (this->gr != gr) rend = 1;
    this->gr = gr;
    rwLock.unlockWrite();
}

void Drawable::setPosition(int x, int y) // sets the position
{
    setPosition(Point(x, y));
}

void Drawable::setSize(int x, int y) // sets the size
{
    setSize(Point(x, y));
}

void Drawable::setWidth(int width)
{
    rwLock.lockWrite();
    if (this->gr.x != width) rend = 1;
    gr.x = width;
    rwLock.unlockWrite();
}

void Drawable::setHeight(int height)
{
    rwLock.lockWrite();
    if (this->gr.y != height) rend = 1;
    gr.y = height;
    rwLock.unlockWrite();
}

bool Drawable::tick(double tickval)
{
    bool r = rend;
    rend = 0;
    return r;
}

void Drawable::setStyle(__int64 style) // sets the style of the text field
{
    if (this->style != style)
    {
        this->style = style;
        rend = 1;
    }
}

void Drawable::setStyle(__int64 style, bool add_remove)
{
    if (add_remove && (this->style | style) != this->style)
    {
        this->style |= style;
        rend = 1;
    }
    else if (!add_remove && (this->style & ~style) != this->style)
    {
        if (toolTip && (style | Style::Visible) == style)
            toolTip->setMouseIn(0);
        this->style &= ~style;
        rend = 1;
    }
}

void Drawable::addStyle(__int64 style)
{
    if ((this->style | style) != this->style)
    {
        this->style |= style;
        rend = 1;
    }
}

void Drawable::removeStyle(__int64 style)
{
    if ((this->style & ~style) != this->style)
    {
        if (toolTip && (style | Style::Visible) == style)
            toolTip->setMouseIn(0);
        this->style &= ~style;
        rend = 1;
    }
}

void Drawable::render(Image& zRObj)
{
    if (toolTip && (style | Style::Visible) == style) toolTip->setDrawing();
}

// constant
bool Drawable::hasMouseEvent() const // checks if Mak is set
{
    return mak != 0;
}

bool Drawable::hasKeyboardEvent() const // checks if Tak is set
{
    return tak != 0;
}

const Point& Drawable::getPosition() const // returns the position
{
    return pos;
}

const Point& Drawable::getSize() const // returns the size
{
    return gr;
}

int Drawable::getWidth() const // returns the width
{
    return gr.x;
}

int Drawable::getHeight() const // returns the height
{
    return gr.y;
}

// Returns the width of the interior area of the drawing in pixels
int Drawable::getInnerWidth() const
{
    return gr.x;
}

// Returns the height of the interior area of the drawing in pixels
int Drawable::getInnerHeight() const
{
    return gr.y;
}

int Drawable::getX() const // returns X
{
    return pos.x;
}

int Drawable::getY() const // returns Y
{
    return pos.y;
}

// Checks if a point is inside this object
//  p: the point
//  return: 1 if the point is inside, 0 otherwise
bool Drawable::isPointInside(Point p) const
{
    return isPointInside(p.x, p.y);
}

// Checks if a point is inside this object
//  x: the x coordinate of the point
//  y: the y coordinate of the point
//  return: 1 if the point is inside, 0 otherwise
bool Drawable::isPointInside(int x, int y) const
{
    return x >= pos.x && x <= pos.x + gr.x && y >= pos.y && y <= pos.y + gr.y;
}

ToolTip* Drawable::getToolTip() const // returns the ToolTip text
{
    return dynamic_cast<ToolTip*>(toolTip->getThis());
}

ToolTip* Drawable::zToolTip() const
{
    return toolTip;
}

bool Drawable::hasStyle(__int64 style) const // checks if style is present
{
    return (this->style | style) == this->style;
}

bool Drawable::hasStyleNot(
    __int64 style) const // checks if style is not present
{
    return (this->style | style) != this->style;
}

__int64 Framework::Drawable::getStyles() const
{
    return style;
}

Drawable* Drawable::duplicate() const // Creates a copy of the drawing
{
    Drawable* obj = new Drawable();
    obj->setPosition(pos);
    obj->setSize(gr);
    obj->setMouseEventParameter(makParam);
    obj->setKeyboardEventParameter(takParam);
    obj->setMouseEvent(mak);
    obj->setKeyboardEvent(tak);
    if (toolTip) obj->setToolTipZ((ToolTip*)toolTip->duplicate());
    return obj;
}

// Contents of the DrawableBackground class from Drawing.h
// Constructor
DrawableBackground::DrawableBackground()
    : Drawable()
{
    backgroundColor = 0xFF000000;
    border = 0;
    backgroundImage = 0;
    backgroundFeld = 0;
    horizontalScrollBar = 0;
    vertikalScrollBar = 0;
    innenPosition.x = 0;
    innenPosition.y = 0;
    innenSize.x = 0;
    innenSize.y = 0;
}

// Destructor
DrawableBackground::~DrawableBackground()
{
    if (border) border->release();
    if (backgroundImage) backgroundImage->release();
    if (backgroundFeld) backgroundFeld->release();
    if (horizontalScrollBar) horizontalScrollBar->release();
    if (vertikalScrollBar) vertikalScrollBar->release();
}

void DrawableBackground::doMouseEvent(MouseEvent& me, bool userRet)
{
    if (userRet)
    {
        int rbr = 0;
        if (hasStyle(Style::Border) && border) rbr = border->getRWidth();
        bool vs = hasStyle(Style::VScroll) && vertikalScrollBar;
        bool hs = hasStyle(Style::HScroll) && horizontalScrollBar;
        if (vs)
        {
            if (hs)
                horizontalScrollBar->doMouseMessage(
                    rbr, gr.y - rbr - 15, gr.x - rbr * 2 - 15, 15, me);
            vertikalScrollBar->doMouseMessage(
                gr.x - rbr - 15, rbr, 15, gr.y - rbr * 2, me);
        }
        else if (hs)
            horizontalScrollBar->doMouseMessage(
                rbr, gr.y - rbr - 15, gr.x - rbr * 2, 15, me);
    }
    me.processed = userRet;
}

void DrawableBackground::setBackgroundImage(
    Image* bild) // sets the background image
{
    if (!backgroundImage) backgroundImage = new Image();
    backgroundImage->newImage(bild->getWidth(), bild->getHeight(), 0);
    int* buff1 = backgroundImage->getBuffer();
    int* buff2 = bild->getBuffer();
    for (int i = 0; i < bild->getWidth() * bild->getHeight(); ++i)
        buff1[i] = buff2[i];
    bild->release();
    rend = 1;
}

void DrawableBackground::setBackgroundImageZ(
    Image* bild) // sets a pointer to the background image
{
    if (backgroundImage != bild)
    {
        if (backgroundImage) backgroundImage->release();
        backgroundImage = bild;
        rend = 1;
    }
}

void DrawableBackground::setBackgroundColor(int fc) // sets the background color
{
    if (backgroundColor != fc)
    {
        backgroundColor = fc;
        rend = 1;
    }
}

void DrawableBackground::setAlphaFieldZ(
    AlphaField* buff) // sets a pointer to the background buffer
{
    if (backgroundFeld != buff)
    {
        if (backgroundFeld) backgroundFeld->release();
        backgroundFeld = buff;
        rend = 1;
    }
}

void DrawableBackground::setAlphaFieldStrength(
    int st) // sets the strength of the background buffer
{
    if (!backgroundFeld)
    {
        backgroundFeld = new AlphaField();
        rend = 1;
    }
    if (backgroundFeld->getStrength() != st)
    {
        backgroundFeld->setStrength(st);
        rend = 1;
    }
}

void DrawableBackground::setAlphaFieldColor(
    int fc) // sets the color of the background buffer
{
    if (!backgroundFeld)
    {
        backgroundFeld = new AlphaField();
        rend = 1;
    }
    if (backgroundFeld->getColor() != fc)
    {
        backgroundFeld->setColor(fc);
        rend = 1;
    }
}

void DrawableBackground::setBorderZ(Border* ram) // sets a pointer to the border
{
    if (border != ram)
    {
        if (border) border->release();
        border = ram;
        rend = 1;
    }
}

void DrawableBackground::setBorderWidth(int br) // sets the border width
{
    if (!border)
    {
        border = new LBorder();
        rend = 1;
    }
    if (border->getRWidth() != br)
    {
        border->setBorderWidth(br);
        rend = 1;
    }
}

void DrawableBackground::setBorderColor(int fc) // sets the border color
{
    if (!border)
    {
        border = new LBorder();
        rend = 1;
    }
    if (border->getColor() != fc)
    {
        border->setColor(fc);
        rend = 1;
    }
}

void DrawableBackground::setVerticalClickScroll(
    int ks) // sets the vertical scroll speed
{
    if (!vertikalScrollBar)
    {
        vertikalScrollBar = new VScrollBar();
        rend = 1;
    }
    if (vertikalScrollBar->getClickScroll() != ks)
    {
        vertikalScrollBar->setClickScroll(ks);
        rend = 1;
    }
}

void DrawableBackground::setVerticalScrollPos(
    int pos) // sets the vertical scroll position
{
    if (!vertikalScrollBar)
    {
        vertikalScrollBar = new VScrollBar();
        rend = 1;
    }
    if (vertikalScrollBar && vertikalScrollBar->getScroll() != pos)
    {
        vertikalScrollBar->scroll(pos);
        rend = 1;
    }
}

void DrawableBackground::setVerticalScrollColor(
    int f, int bgF) // sets the scroll color
{
    if (!vertikalScrollBar)
    {
        vertikalScrollBar = new VScrollBar();
        rend = 1;
    }
    if (vertikalScrollBar
        && (vertikalScrollBar->getColor() != f
            || vertikalScrollBar->getBgColor() != bgF))
    {
        vertikalScrollBar->setColor(f);
        vertikalScrollBar->setBgColor(bgF, bgF != 0);
        rend = 1;
    }
}

void DrawableBackground::setHorizontalClickScroll(
    int ks) // sets the horizontal scroll speed
{
    if (!horizontalScrollBar)
    {
        horizontalScrollBar = new HScrollBar();
        rend = 1;
    }
    if (horizontalScrollBar && horizontalScrollBar->getClickScroll() != ks)
    {
        horizontalScrollBar->setClickScroll(ks);
        rend = 1;
    }
}

void DrawableBackground::setHorizontalScrollPos(
    int pos) // sets the horizontal scroll position
{
    if (!horizontalScrollBar)
    {
        horizontalScrollBar = new HScrollBar();
        rend = 1;
    }
    if (horizontalScrollBar && horizontalScrollBar->getScroll() != pos)
    {
        horizontalScrollBar->scroll(pos);
        rend = 1;
    }
}

void DrawableBackground::setHorizontalScrollColor(
    int f, int bgF) // sets the scroll color
{
    if (!horizontalScrollBar)
    {
        horizontalScrollBar = new HScrollBar();
        rend = 1;
    }
    if (horizontalScrollBar
        && (horizontalScrollBar->getColor() != f
            || horizontalScrollBar->getBgColor() != bgF))
    {
        horizontalScrollBar->setColor(f);
        horizontalScrollBar->setBgColor(bgF, bgF != 0);
        rend = 1;
    }
}

bool DrawableBackground::tick(double tickVal)
{
    if (vertikalScrollBar && hasStyle(Style::VScroll))
        rend |= vertikalScrollBar->getNeedRender();
    if (horizontalScrollBar && hasStyle(Style::HScroll))
        rend |= horizontalScrollBar->getNeedRender();
    return Drawable::tick(tickVal);
}

void DrawableBackground::render(Image& rObj)
{
    innenPosition.x = pos.x;
    innenPosition.y = pos.y;
    innenSize.x = gr.x;
    innenSize.y = gr.y;
    if (hasStyleNot(Style::Visible)) return;
    rwLock.lockRead();
    if (!rObj.setDrawOptions(pos.x, pos.y, gr.x, gr.y))
    {
        rwLock.unlockRead();
        return;
    }
    Drawable::render(rObj);
    int rbr = 0;
    if (hasStyle(Style::Border) && border)
    {
        border->setSize(gr);
        border->render(rObj);
        rbr = border->getRWidth();
    }
    innenPosition.x += rbr;
    innenPosition.y += rbr;
    innenSize.x -= rbr * 2;
    innenSize.y -= rbr * 2;
    if (!rObj.setDrawOptions(rbr, rbr, gr.x - rbr * 2, gr.y - rbr * 2))
    {
        rObj.releaseDrawOptions();
        rwLock.unlockRead();
        return;
    }
    bool vs = vertikalScrollBar && hasStyle(Style::VScroll);
    bool hs = horizontalScrollBar && hasStyle(Style::HScroll);
    if (vs)
    {
        vertikalScrollBar->render(
            gr.x - rbr * 2 - 15, 0, 15, gr.y - rbr * 2, rObj);
        innenSize.x -= 15;
        if (hs)
        {
            horizontalScrollBar->render(
                0, gr.y - rbr * 2 - 15, gr.x - rbr * 2 - 15, 15, rObj);
            innenSize.y -= 15;
            if (!rObj.setDrawOptions(
                    0, 0, gr.x - rbr * 2 - 15, gr.y - rbr * 2 - 15))
            {
                rObj.releaseDrawOptions();
                rObj.releaseDrawOptions();
                rwLock.unlockRead();
                return;
            }
            horizontalScrollBar->update(
                horizontalScrollBar->getScrollData()->max, innenSize.x);
        }
        else
        {
            if (!rObj.setDrawOptions(0, 0, gr.x - rbr * 2 - 15, gr.y - rbr * 2))
            {
                rObj.releaseDrawOptions();
                rObj.releaseDrawOptions();
                rwLock.unlockRead();
                return;
            }
        }
        vertikalScrollBar->update(
            vertikalScrollBar->getScrollData()->max, innenSize.y);
    }
    else if (hs)
    {
        horizontalScrollBar->render(
            rbr, gr.y - rbr * 2 - 15, gr.x - rbr * 2, 15, rObj);
        innenSize.y -= 15;
        if (!rObj.setDrawOptions(0, 0, gr.x - rbr * 2, gr.y - rbr * 2 - 15))
        {
            rObj.releaseDrawOptions();
            rObj.releaseDrawOptions();
            rwLock.unlockRead();
            return;
        }
    }
    if (hasStyle(Style::Background))
    {
        if (hasStyle(Style::BAlpha))
            rObj.alphaRegion(
                0, 0, gr.x - rbr * 2, gr.y - rbr * 2, backgroundColor);
        else
            rObj.fillRegion(
                0, 0, gr.x - rbr * 2, gr.y - rbr * 2, backgroundColor);
        if (hasStyle(Style::BImage) && backgroundImage)
        {
            if (hasStyle(Style::BImageScale))
            {
                if (hasStyle(Style::BAlpha))
                    rObj.alphaImageScaled(
                        0, 0, gr.x - rbr * 2, gr.y - rbr * 2, *backgroundImage);
                else
                    rObj.drawImageScaled(
                        0, 0, gr.x - rbr * 2, gr.y - rbr * 2, *backgroundImage);
            }
            else
            {
                int x = (gr.x - rbr * 2 - backgroundImage->getSize().x) / 2;
                int y = (gr.y - rbr * 2 - backgroundImage->getSize().y) / 2;
                if (hasStyle(Style::BAlpha))
                    rObj.alphaImage(
                        x, y, gr.x - rbr * 2, gr.y - rbr * 2, *backgroundImage);
                else
                    rObj.drawImage(
                        x, y, gr.x - rbr * 2, gr.y - rbr * 2, *backgroundImage);
            }
        }
    }
    if (hasStyle(Style::Buffered) && backgroundFeld)
    {
        backgroundFeld->setSize(gr.x - rbr * 2, gr.y - rbr * 2);
        backgroundFeld->render(rObj);
    }
    if (vs || hs) rObj.releaseDrawOptions();
    rObj.releaseDrawOptions();
    rObj.releaseDrawOptions();
    rwLock.unlockRead();
}

// Returns the width of the interior area of the drawing in pixels
int DrawableBackground::getInnerWidth() const
{
    return getWidth() - 2 * getBorderWidth();
}

// Returns the height of the interior area of the drawing in pixels
int DrawableBackground::getInnerHeight() const
{
    return getHeight() - 2 * getBorderWidth();
}

Image*
DrawableBackground::getBackgroundImage() const // returns the background image
{
    if (!backgroundImage) return 0;
    return dynamic_cast<Image*>(backgroundImage->getThis());
}

Image* DrawableBackground::zBackgroundImage()
    const // returns the background image without increased reference counter
{
    return backgroundImage;
}

int DrawableBackground::getBackgroundColor()
    const // returns the background color
{
    return backgroundColor;
}

AlphaField*
DrawableBackground::getAlphaField() const // returns the background buffer
{
    if (!backgroundFeld) return 0;
    return dynamic_cast<AlphaField*>(backgroundFeld->getThis());
}

AlphaField* DrawableBackground::zAlphaField()
    const // returns the background buffer without increased reference counter
{
    return backgroundFeld;
}

int DrawableBackground::getAlphaFieldStrength()
    const // returns the strength of the background buffer
{
    if (!backgroundFeld) return 0;
    return backgroundFeld->getStrength();
}

int DrawableBackground::getAlphaFieldColor()
    const // returns the color of the background buffer
{
    return backgroundFeld->getColor();
}

Border* DrawableBackground::getBorder() const // returns the border
{
    if (!border) return 0;
    return dynamic_cast<Border*>(border->getThis());
}

Border* DrawableBackground::zBorder()
    const // returns the border without increased reference counter
{
    return border;
}

int DrawableBackground::getBorderWidth() const // returns the border width
{
    if (!border || hasStyleNot(Style::Border)) return 0;
    return border->getRWidth();
}

int DrawableBackground::getBorderColor() const // returns the border color
{
    return border->getColor();
}

int DrawableBackground::getVerticalClickScroll() const
{
    return vertikalScrollBar ? vertikalScrollBar->getClickScroll() : 0;
}

int DrawableBackground::getVerticalScrollPos() const
{
    return vertikalScrollBar ? vertikalScrollBar->getScroll() : 0;
}

int DrawableBackground::getVerticalScrollColor() const
{
    return vertikalScrollBar ? vertikalScrollBar->getColor() : 0;
}

int DrawableBackground::getVerticalScrollBackground() const
{
    return vertikalScrollBar ? vertikalScrollBar->getBgColor() : 0;
}

int DrawableBackground::getHorizontalClickScroll() const
{
    return horizontalScrollBar ? horizontalScrollBar->getClickScroll() : 0;
}

int DrawableBackground::getHorizontalScrollPos() const
{
    return horizontalScrollBar ? horizontalScrollBar->getScroll() : 0;
}

int DrawableBackground::getHorizontalScrollColor() const
{
    return horizontalScrollBar ? horizontalScrollBar->getColor() : 0;
}

int DrawableBackground::getHorizontalScrollBackground() const
{
    return horizontalScrollBar ? horizontalScrollBar->getBgColor() : 0;
}

Drawable* DrawableBackground::duplicate() const // Creates a copy of the drawing
{
    DrawableBackground* obj = new DrawableBackground();
    obj->setPosition(pos);
    obj->setSize(gr);
    obj->setMouseEventParameter(makParam);
    obj->setKeyboardEventParameter(takParam);
    obj->setMouseEvent(mak);
    obj->setKeyboardEvent(tak);
    if (toolTip) obj->setToolTipZ((ToolTip*)toolTip->duplicate());
    obj->setStyle(style);
    obj->setBackgroundColor(backgroundColor);
    if (backgroundFeld)
        obj->setAlphaFieldZ((AlphaField*)backgroundFeld->duplicate());
    if (border) obj->setBorderZ((Border*)border->duplicate());
    if (backgroundImage)
        obj->setBackgroundImage(
            dynamic_cast<Image*>(backgroundImage->getThis()));
    if (vertikalScrollBar)
    {
        obj->setVerticalClickScroll(vertikalScrollBar->getClickScroll());
        obj->setVerticalScrollPos(vertikalScrollBar->getScroll());
        obj->setVerticalScrollColor(
            vertikalScrollBar->getColor(), vertikalScrollBar->getBgColor());
    }
    if (horizontalScrollBar)
    {
        obj->setHorizontalClickScroll(horizontalScrollBar->getClickScroll());
        obj->setHorizontalScrollPos(horizontalScrollBar->getScroll());
        obj->setHorizontalScrollColor(
            horizontalScrollBar->getColor(), horizontalScrollBar->getBgColor());
    }
    return obj;
}