Subversion Repositories tpanel

Rev

Rev 319 | Blame | Last modification | View Log | RSS feed

/*
 * Copyright (C) 2023 by Andreas Theofilu <andreas@theosys.at>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 */

#include <QWidget>
#include <QScrollArea>
#include <QPixmap>
#include <QColor>
#include <QPainter>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QPoint>
#include <QMouseEvent>
#include <QScrollBar>
#include <QTimer>

#include "tqscrollarea.h"
#include "terror.h"
#include "tresources.h"

using std::vector;

/**
 * @brief TQScrollArea::TQScrollArea
 * Constructor for the class.
 */
TQScrollArea::TQScrollArea()
{
    DECL_TRACER("TQScrollArea::TQScrollArea()");
}

/**
 * @brief TQScrollArea::TQScrollArea
 * @param parent    The parent widget
 */
TQScrollArea::TQScrollArea(QWidget* parent)
    : mParent(parent)
{
    DECL_TRACER("TQScrollArea::TQScrollArea(QWidget* parent)");

    if (parent)
    {
        mWidth = parent->geometry().width();
        mHeight = parent->geometry().height();
    }

    init();
}

/**
 * @brief TQScrollArea::TQScrollArea
 * @param parent        Parent widget
 * @param w             Visible width in pixels
 * @param h             Visible height in pixels
 * @param vertical      TRUE: Scrolling in vertical direction
 */
TQScrollArea::TQScrollArea(QWidget* parent, int w, int h, bool vertical)
    : mParent(parent),
      mVertical(vertical)
{
    DECL_TRACER("TQScrollArea::TQScrollArea(QWidget* parent, int w, int h, bool vertical)");

    if (w > 0)
        mWidth = w;

    if (h > 0)
        mHeight = h;

    init();
}

/**
 * @brief TQScrollArea::TQScrollArea
 * @param parent    Parent widget
 * @param size      Size (width and height) of visible area
 * @param vertical  TRUE: Scrolling in vertical direction
 */
TQScrollArea::TQScrollArea(QWidget* parent, const QSize& size, bool vertical)
    : mParent(parent),
      mVertical(vertical)
{
    DECL_TRACER("TQScrollArea::TQScrollArea(QWidget* parent, const QSize& size, bool vertical)");

    if (size.width() > 0)
        mWidth = size.width();

    if (size.height() > 0)
        mHeight = size.height();

    init();
}

TQScrollArea::~TQScrollArea()
{
    DECL_TRACER("TQScrollArea::~TQScrollArea()");

    if (mMain)
        mMain->close();

    if (mMousePressTimer)
    {
        if (mMousePressTimer->isActive())
            mMousePressTimer->stop();

        disconnect(mMousePressTimer, &QTimer::timeout, this, &TQScrollArea::mouseTimerEvent);
        delete mMousePressTimer;
        mMousePressTimer = nullptr;
    }
}

void TQScrollArea::init()
{
    DECL_TRACER("TQScrollArea::init()");

    QScrollArea::setParent(mParent);
    QScrollArea::setViewportMargins(0, 0, 0, 0);

    if (mWidth > 0 || mHeight > 0)
        QScrollArea::setFixedSize(mWidth, mHeight);

    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    // Set a transparent background
    QPalette palette(this->palette());
    palette.setColor(QPalette::Window, Qt::transparent);
    setPalette(palette);

    if (!mMain)
        mMain = new QWidget(this);

    mMain->move(0, 0);
    mMain->setContentsMargins(0, 0, 0, 0);

    if (mWidth && mHeight)
        setFixedSize(mWidth, mHeight);

    setWidget(mMain);

    if (mVertical && !mVLayout)
    {
        mVLayout = new QVBoxLayout(mMain);
        mVLayout->setSpacing(0);
        mVLayout->setContentsMargins(0, 0, 0, 0);
    }
    else if (!mVertical && !mHLayout)
    {
        mHLayout = new QHBoxLayout(mMain);
        mHLayout->setSpacing(0);
        mHLayout->setContentsMargins(0, 0, 0, 0);
    }


    if (!mTotalWidth)
        mTotalWidth = mWidth;

    if (!mTotalHeight)
        mTotalHeight = mHeight;
}

/**
 * @brief TQScrollArea::setObjectName
 * This sets the object name of the internal main QWidget.
 *
 * @param name  The name of the object.
 */
void TQScrollArea::setObjectName(const QString& name)
{
    DECL_TRACER("TQScrollArea::setObjectName(const QString& name)");

    if (mMain)
        mMain->setObjectName(name);
}

/**
 * @brief TQScrollArea::setSize
 * Sets the size of the visible area of the object.
 *
 * @param w     The width in pixels
 * @param h     The height in pixels
 */
void TQScrollArea::setSize(int w, int h)
{
    DECL_TRACER("TQScrollArea::setSize(int w, int h)");

    if (w < 1 || h < 1)
        return;

    mWidth = w;
    mHeight = h;
    setFixedSize(mWidth, mHeight);
}

/**
 * @brief TQScrollArea::setSize
 * Sets the size of the visible area of the object.
 *
 * @param size  The size (width and height)
 */
void TQScrollArea::setSize(QSize size)
{
    DECL_TRACER("TQScrollArea::setSize(QSize size)");

    mWidth = size.width();
    mHeight = size.height();
    setFixedSize(mWidth, mHeight);
}

/**
 * @brief TQScrollArea::getSize
 * Returns the size of the visible area.
 *
 * @return A QSize object containg the size in pixels.
 */
QSize TQScrollArea::getSize()
{
    DECL_TRACER("TQScrollArea::getSize()");

    return QSize(mWidth, mHeight);
}

/**
 * @brief TQScrollArea::setScrollbar
 * Makes the scrollbar visible or invisible.
 *
 * @param sb    TRUE: The scrollbar is set to visible. It depends on the type
 *              of scroll area. On vertical areas the bottom scrollbar may
 *              become visible and on horizontal areas the right one.
 */
void TQScrollArea::setScrollbar(bool sb)
{
    DECL_TRACER("TQScrollArea::setScrollbar(bool sb)");

    if (sb == mScrollbar)
        return;

    mScrollbar = sb;

    if (sb)
    {
        if (mVertical)
            setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
        else
            setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
    }
    else
    {
        if (mVertical)
            setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
        else
            setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    }
}

/**
 * @brief TQScrollArea::setScrollbarOffset
 * Positions the scrollbar to the \b offset position. On a vertical scroll
 * area the offset is alway the top visible pixel line and on horizontal
 * scroll areas it is the left visible pixel.
 *
 * @param offset    The offset position. If this is less then 0 or grater then
 *                  the whole size, the value is ignored.
 */
void TQScrollArea::setScrollbarOffset(int offset)
{
    DECL_TRACER("TQScrollArea::setScrollbarOffset(int offset)");

    if (!mScrollbar)
        return;

    if (offset <= 0)
        mScrollbarOffset = 0;
    else
        mScrollbarOffset = scale(offset);

    QScrollBar *sbar = nullptr;

    if (mVertical)
        sbar = verticalScrollBar();
    else
        sbar = horizontalScrollBar();

    if (sbar)
    {
        if (mScrollbarOffset > (mVertical ? sbar->pos().y() : sbar->pos().x()))
            mScrollbarOffset = (mVertical ? sbar->pos().y() : sbar->pos().x());

        sbar->setSliderPosition(mScrollbarOffset);
    }
}

/**
 * @brief TQScrollArea::setAnchor
 * Sets the anchor position. This can be left, center or right for horizontal
 * scroll areas or top, center or bottom for vertical.
 * The anchor position is the one the items scroll to if they should appear at
 * this position. The center position is the default one.
 *
 * @param position  Defines the anchor position.
 */
void TQScrollArea::setAnchor(Button::SUBVIEW_POSITION_t position)
{
    DECL_TRACER("TQScrollArea::setAnchor(Button::SUBVIEW_POSITION_t position)");

    mPosition = position;

    if (!mWrapItems)
    {
        QWidget *w = mMain->childAt(mWidth / 2, mHeight / 2);

        if (w)
            setPosition(w, 0);
    }
    else
        setPosition();
}

/**
 * @brief TQScrollArea::show
 * Shows all items in the scroll area. If some were invisible or not enabled,
 * they are visible and enabled. Depending on the set anchor position the
 * whole area is set to it. This means for example, that the center item is
 * moved into the view area if the anchor position is set to SVP_CENTER.
 */
void TQScrollArea::show()
{
    DECL_TRACER("TQScrollArea::show()");

    if (!QScrollArea::isEnabled())
        QScrollArea::setEnabled(true);

    QScrollArea::show();

    if (mMain)
    {
        if (!mMain->isEnabled())
            mMain->setEnabled(true);

        if (!mMain->isVisible())
            mMain->show();
    }

    if (mWrapItems)
        setPosition();
}

/**
 * @brief TQScrollArea::setTotalWidth
 * Sets the total width of the scrolling area. This must be equal or grater
 * then the width of the visible area.
 *
 * @param w The width in pixels.
 */
void TQScrollArea::setTotalWidth(int w)
{
    DECL_TRACER("TQScrollArea::setTotalWidth(int w)");

    if (!mMain || w < mWidth)
        return;

    mTotalWidth = w;
    mMain->setFixedWidth(mTotalWidth);
}

/**
 * @brief TQScrollArea::setTotalHeight
 * Sets the total height of the scrolling area. This must be equal or grater
 * then the height of the visible area.
 *
 * @param h  The height in pixels.
 */
void TQScrollArea::setTotalHeight(int h)
{
    DECL_TRACER("TQScrollArea::setTotalHeight(int h)");

    if (!mMain || h < mHeight)
        return;

    mTotalHeight = h;
    mMain->setFixedHeight(mTotalHeight);
}

/**
 * @brief TQScrollArea::setTotalSize
 * Sets the total size of the scrolling area. The width and height must be
 * equal or grater then the width and height of the visible area.
 *
 * @param w  The width in pixels.
 * @param h  The height in pixels.
 */
void TQScrollArea::setTotalSize(int w, int h)
{
    DECL_TRACER("TQScrollArea::setTotalSize(int w, int h)");

    if (!mMain || w < mWidth || h < mHeight)
        return;

    mTotalWidth = w;
    mTotalHeight = h;
    mMain->setFixedSize(mTotalWidth, mTotalHeight);
}

/**
 * @brief TQScrollArea::setTotalSize
 * Sets the total size of the scrolling area in pixels.
 *
 * @param size  The total size of the scrolling area.
 */
void TQScrollArea::setTotalSize(QSize& size)
{
    DECL_TRACER("TQScrollArea::setTotalSize(QSize& size)");

    if (!mMain || size.width() < mWidth || size.height() < mHeight)
        return;

    mTotalWidth = size.width();
    mTotalHeight = size.height();
    mMain->setFixedSize(mTotalWidth, mTotalHeight);
}

/**
 * @brief TQScrollArea::setBackgroundImage
 * This sets the background image of the scroll area. If the pixmap is smaller
 * then the total size, the image is painted in tiles.
 *
 * @param pix       The pixmap.
 */
void TQScrollArea::setBackgroundImage(const QPixmap& pix)
{
    DECL_TRACER("TQScrollArea::setBackgroundImage(const QPixmap& pix)");

    if (!mMain || pix.isNull())
        return;

    QPalette palette(mMain->palette());
    palette.setBrush(QPalette::Window, QBrush(pix));
    mMain->setPalette(palette);
}

/**
 * @brief TQScrollArea::setBackGroundColor
 * Sets the background color of the scroll area.
 *
 * @param color     The color
 */
void TQScrollArea::setBackGroundColor(QColor color)
{
    DECL_TRACER("TQScrollArea::setBackGroundColor(QColor color)");

    if (!mMain)
        return;

    QPalette palette(mMain->palette());
    palette.setColor(QPalette::Window, color);
    mMain->setPalette(palette);
}

/**
 * @brief TQScrollArea::setSpace
 * Sets the space between the items in percent. The pixels are calculated
 * from the total size of the scroll area. Then the spce is inserted.
 *
 * @param s     A value between 0 and 99. 0 Removes the space.
 */
void TQScrollArea::setSpace(int s)
{
    DECL_TRACER("TQScrollArea::setSpace(double s)");

    if (s < 0 || s > 99 || mSpace == s)
        return;

    mSpace = s;
    refresh();
}

/**
 * @brief TQScrollArea::addItem
 * Adds one item to the list of items.
 *
 * @param item  Item to add
 */
void TQScrollArea::addItem(PGSUBVIEWITEM_T& item)
{
    DECL_TRACER("TQScrollArea::addItem(PGSUBVIEWITEM_T& item)");

    _clearAllItems();
    resetSlider();
    mItems.push_back(subViewItemToItem(item));
    _addItems(mItems, true);
}

/**
 * @brief TQScrollArea::addItems
 * Adds one or more items to the scroll area and sizes the scroll area large
 * enough to hold all items. It calculates also the space between the items.
 * If there were already some items visible, they are deleted first. Then they
 * are displayed again.
 *
 * @param items     A list of items to be displayed
 * @param intern    TRUE: The list of items is not stored internal.
 */
void TQScrollArea::addItems(std::vector<PGSUBVIEWITEM_T>& items)
{
    DECL_TRACER("TQScrollArea::addItems(std::vector<PGSUBVIEWITEM_T>& items, bool intern)");

    if (items.empty())
        return;

    _clearAllItems();
    resetSlider();
    mItems.clear();

    vector<PGSUBVIEWITEM_T>::iterator iter;

    for (iter = items.begin(); iter != items.end(); ++iter)
        mItems.push_back(subViewItemToItem(*iter));

    _addItems(mItems, true);
}

void TQScrollArea::_addItems(std::vector<_ITEMS_T>& items, bool intern)
{
    DECL_TRACER("_addItems(std::vector<ITEMS_T>& items, bool intern)");

    mWrapItems = items[0].wrap;     // Endless scroll

    if (!intern)
        mItems = items;             // Store the items to the internal vector array

    if (mVertical)
        mTotalHeight = 0;
    else
        mTotalWidth = 0;

    int total = 0;                  // The total width or height
    vector<_ITEMS_T>::iterator iter;
    // First calculate the total width and height if it was not set by a previous call
    if ((mTotalWidth <= 0 && !mVertical) || (mTotalHeight <= 0 && mVertical))
    {
        if (mTotalWidth <= 0)
            mTotalWidth = mWidth;

        if (mTotalHeight <= 0)
            mTotalHeight = mHeight;

        if (!mVertical || mTotalWidth <= 0)
            mTotalWidth = 0;

        if (mVertical || mTotalHeight <= 0)
            mTotalHeight = 0;

        int num = 0;

        for (iter = items.begin(); iter != items.end(); ++iter)
        {
            if (!mVertical)
                mTotalWidth += iter->width;
            else
                mTotalHeight += iter->height;

            num++;
        }

        if (mVertical)
        {
            mTotalHeight = scale(mTotalHeight);
            total = mTotalHeight;
        }
        else
        {
            mTotalWidth = scale(mTotalWidth);
            total = mTotalWidth;
        }

        if (mMain)
            mMain->setFixedSize(mTotalWidth, mTotalHeight);
    }

    MSG_DEBUG("Number of items: " << items.size());

    if (mSpace > 0)
    {
        int space = (int)((double)total / 100.0 * (double)mSpace);

        if (space > 0 && mVertical && mVLayout && mMain)
        {
            int newHeight = space + mTotalHeight;
            mMain->setFixedHeight(newHeight);
            MSG_DEBUG("Calculated space: " << space << " (" << mSpace << "%). Total height: " << newHeight << ", Old total height: " << mTotalHeight);
            mTotalHeight = newHeight;
        }
        else if (space > 0 && !mVertical && mHLayout && mMain)
        {
            int newWidth = space + mTotalWidth;
            mMain->setFixedWidth(newWidth);
            MSG_DEBUG("Calculated space: " << space << " (" << mSpace << "%). Total width: " << newWidth << ", Old total width: " << mTotalWidth);
            mTotalWidth = newWidth;
        }
    }

    for (iter = items.begin(); iter != items.end(); ++iter)
    {
        int iWidth = scale(iter->width);
        int iHeight = scale(iter->height);
        QWidget *item = new QWidget;
        item->setObjectName(QString("Item_%1").arg(handleToString(iter->handle).c_str()));
        item->setFixedSize(iWidth, iHeight);
        item->setAutoFillBackground(true);
        QColor bgcolor(qRgba(iter->bgcolor.red, iter->bgcolor.green, iter->bgcolor.blue, iter->bgcolor.alpha));

        if (iter->image.getSize() > 0)
        {
            QPixmap pixmap(iWidth, iHeight);

            if (iter->bgcolor.alpha == 0)
                pixmap.fill(Qt::transparent);
            else
                pixmap.fill(bgcolor);

            QImage img(iter->image.getBitmap(), iter->image.getWidth(), iter->image.getHeight(), iter->image.getPixline(), QImage::Format_ARGB32);  // Original size
            bool ret = false;

            if (mScaleFactor != 1.0)
            {
                QSize size(iWidth, iHeight);
                ret = pixmap.convertFromImage(img.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));   // Scaled size
            }
            else
                ret = pixmap.convertFromImage(img);

            if (!ret || pixmap.isNull())
            {
                MSG_ERROR("Unable to create a pixmap out of an image!");
                return;
            }

            QPalette palette(item->palette());
            palette.setBrush(QPalette::Window, QBrush(pixmap));
            item->setPalette(palette);
        }
        else
        {
            QPalette palette(item->palette());

            if (iter->bgcolor.alpha == 0)
                palette.setColor(QPalette::Window, Qt::transparent);
            else
                palette.setColor(QPalette::Window, bgcolor);

            item->setPalette(palette);
        }

        // Add the buttons to the item widget
        if (iter->atoms.empty())
        {
            delete item;
            continue;
        }

        vector<PGSUBVIEWATOM_T>::iterator itAtom;

        for (itAtom = iter->atoms.begin(); itAtom != iter->atoms.end(); ++itAtom)
        {
            int scaWidth = scale(itAtom->width);
            int scaHeight = scale(itAtom->height);

            QLabel *label = new QLabel(item);
            label->move(scale(itAtom->left), scale(itAtom->top));
            label->setFixedSize(scaWidth, scaHeight);
            label->setObjectName(QString("Label_%1").arg(handleToString(itAtom->handle).c_str()));
            setAtom(*itAtom, label);
        }

        iter->item = item;

        if (mVertical && mVLayout)
            mVLayout->addWidget(item);
        else if (!mVertical && mHLayout)
            mHLayout->addWidget(item);
        else
        {
            MSG_ERROR("Layout not initialized!");
        }
    }

    if (mOldActPosition > 0)
    {
        MSG_DEBUG("Setting position to old value " << mOldActPosition);
        resetSlider(mOldActPosition);
        mOldActPosition = 0;
    }
}

/**
 * @brief TQScrollArea::updateItem
 * Updates one item.
 *
 * @param item  The item to update.
 */
void TQScrollArea::updateItem(PGSUBVIEWITEM_T& item)
{
    DECL_TRACER("TQScrollArea::updateItem(PGSUBVIEWITEM_T& item)");

    if (mItems.empty())
        return;

    vector<_ITEMS_T>::iterator iter;

    for (iter = mItems.begin(); iter != mItems.end(); ++iter)
    {
        if (iter->handle == item.handle)
        {
            iter->bgcolor = item.bgcolor;
            iter->bounding = item.bounding;
            iter->image = item.image;
            iter->atoms = item.atoms;

            if (!iter->atoms.empty())
            {
                QObjectList list = iter->item->children();
                QList<QObject *>::Iterator obit;
                vector<PGSUBVIEWATOM_T>::iterator atit;

                for (atit = iter->atoms.begin(); atit != iter->atoms.end(); ++atit)
                {
                    for (obit = list.begin(); obit != list.end(); ++obit)
                    {
                        QObject *o = *obit;
                        QString obname = o->objectName();
                        ulong atHandle = extractHandle(obname.toStdString());

                        if (atit->handle == atHandle && obname.startsWith("Label_"))
                        {
                            QLabel *lbl = dynamic_cast<QLabel *>(o);
                            setAtom(*atit, lbl);
                            break;
                        }
                    }
                }

                iter->item->show();
            }

            break;
        }
    }
}

void TQScrollArea::showItem(ulong handle, int position)
{
    DECL_TRACER("TQScrollArea::showItem(ulong handle, int position)");

    if (mItems.empty())
        return;

    vector<_ITEMS_T>::iterator iter;

    for (iter = mItems.begin(); iter != mItems.end(); ++iter)
    {
        if (!iter->item)
            continue;

        if (iter->handle == handle)
        {
            if (!iter->item->isVisible())
                iter->item->setVisible(true);

            setPosition(iter->item, position);
            break;
        }
    }
}

void TQScrollArea::toggleItem(ulong handle, int position)
{
    DECL_TRACER("TQScrollArea::toggleItem(ulong handle, int position)");

    if (mItems.empty())
        return;

    vector<_ITEMS_T>::iterator iter;

    for (iter = mItems.begin(); iter != mItems.end(); ++iter)
    {
        if (iter->handle == handle && iter->item)
        {
            if (iter->item->isVisible())
                iter->item->setVisible(false);
            else
            {
                iter->item->setVisible(true);
                setPosition(iter->item, position);
            }

            break;
        }
    }
}

void TQScrollArea::hideAllItems()
{
    DECL_TRACER("TQScrollArea::hideAllItems()");

    if (mItems.empty())
        return;

    resetSlider();
    vector<_ITEMS_T>::iterator iter;

    for (iter = mItems.begin(); iter != mItems.end(); ++iter)
    {
        if (iter->item)
            iter->item->setVisible(false);
    }
}

void TQScrollArea::hideItem(ulong handle)
{
    DECL_TRACER("TQScrollArea::hideItem(ulong handle)");

    if (mItems.empty())
        return;

    vector<_ITEMS_T>::iterator iter;

    for (iter = mItems.begin(); iter != mItems.end(); ++iter)
    {
        if (iter->handle == handle && iter->item)
        {
            iter->item->setVisible(false);
            return;
        }
    }
}

int TQScrollArea::scale(int value)
{
    DECL_TRACER("TQScrollArea::scale(int value)");

    if (mScaleFactor != 1.0)
        return (int)((double)value * mScaleFactor);

    return value;
}

void TQScrollArea::setScaleFactor(const double& factor)
{
    DECL_TRACER("TQScrollArea::setScaleFactor(const double& factor)");

    if (factor > 0.0 && factor != 1.0)
        mScaleFactor = factor;
}

void TQScrollArea::setAtom(PGSUBVIEWATOM_T& atom, QLabel *label)
{
    DECL_TRACER("TQScrollArea::setAtom(PGSUBVIEWATOM_T& atom, QLabel *label)");

    if (!label)
        return;

    int scaWidth = scale(atom.width);
    int scaHeight = scale(atom.height);
    QColor bg(qRgba(atom.bgcolor.red, atom.bgcolor.green, atom.bgcolor.blue, atom.bgcolor.alpha));

    if (atom.image.isValid())
    {
        QPixmap pix(scaWidth, scaHeight);

        if (atom.bgcolor.alpha == 0)
            pix.fill(Qt::transparent);
        else
            pix.fill(bg);

        QImage img(atom.image.getBitmap(), atom.image.getWidth(), atom.image.getHeight(), atom.image.getPixline(), QImage::Format_ARGB32);
        bool ret = false;

        if (mScaleFactor != 1.0)
        {
            QSize size(scaWidth, scaHeight);
            ret = pix.convertFromImage(img.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); // Scaled size
        }
        else
            ret = pix.convertFromImage(img);

        if (!ret || pix.isNull())
        {
            MSG_ERROR("Unable to create a pixmap out of an image!");
            return;
        }

        label->setPixmap(pix);
    }
    else
    {
        QPalette palette(label->palette());

        if (atom.bgcolor.alpha == 0)
            palette.setColor(QPalette::Window, Qt::transparent);
        else
            palette.setColor(QPalette::Window, bg);

        label->setPalette(palette);
    }
}

void TQScrollArea::refresh()
{
    DECL_TRACER("TQScrollArea::refresh()");

    if (!mMain || mItems.empty())
        return;

    resetSlider();
    _clearAllItems();
    _addItems(mItems, true);
}

void TQScrollArea::setPosition()
{
    DECL_TRACER("TQScrollArea::setPosition()");

    if (mItems.empty())
        return;

    QWidget *anchor = nullptr;
    size_t pos = 0;
    MSG_DEBUG("Wrap items: " << (mWrapItems ? "TRUE" : "FALSE") << ", number items: " << mItems.size());

    switch (mPosition)
    {
        case Button::SVP_LEFT_TOP:
            anchor = mItems[0].item;
        break;

        case Button::SVP_CENTER:
            pos = mItems.size() / 2;
            anchor = mItems[pos].item;
        break;

        case Button::SVP_RIGHT_BOTTOM:
            pos = mItems.size() - 1;
            anchor = mItems[pos].item;
        break;
    }

    if (anchor)
    {
        QRect geom = anchor->geometry();
        bool makeVisible = false;

        if (mVertical)
        {
            if ((geom.y() + geom.height()) < mActPosition ||
                    geom.y() > (mActPosition + mHeight))
                makeVisible = true;
        }
        else
        {
            if ((geom.x() + geom.width()) < mActPosition ||
                    geom.x() > (mActPosition + mWidth))
                makeVisible = true;
        }

        ulong handle = extractHandle(anchor->objectName().toStdString());

        if (makeVisible)
        {
            ensureWidgetVisible(anchor);
            MSG_DEBUG("Item number " << pos << " (" << handleToString(handle) << ") was moved to position.");
        }
        else
        {
            MSG_DEBUG("Item number " << pos << " (" << handleToString(handle) << ") is already at visible position.");
        }
    }
}

void TQScrollArea::setPosition(QWidget* w, int position)
{
    DECL_TRACER("TQScrollArea::setPosition(QWidget* w, int position)");

    int defPosX = 50;
    int defPosY = 50;

    if (position > 0 && position < 65535)
    {
        if (mVertical)
        {
            defPosY = position;
            defPosX = 0;
        }
        else
        {
            defPosY = position;
            defPosX = 0;
        }

        ensureWidgetVisible(w, defPosX, defPosY);
    }
    else if (mPosition == Button::SVP_LEFT_TOP)
    {
        if (mVertical)
        {
            int top = w->geometry().y();
            QScrollBar *bar = verticalScrollBar();

            if (bar)
                bar->setSliderPosition(top);
        }
        else
        {
            int left = w->geometry().x();
            QScrollBar *bar = horizontalScrollBar();

            if (bar)
                bar->setSliderPosition(left);
        }
    }
    else if (mPosition == Button::SVP_CENTER)
    {
        if (mVertical)
        {
            int topMargin = (mHeight - w->geometry().height()) / 2;
            int top = w->geometry().y() - topMargin;
            QScrollBar *bar = verticalScrollBar();

            if (bar)
                bar->setSliderPosition(top);
        }
        else
        {
            int leftMargin = (mWidth - w->geometry().width()) / 2;
            int left = w->geometry().x() - leftMargin;
            QScrollBar *bar = horizontalScrollBar();

            if (bar)
                bar->setSliderPosition(left);
        }
    }
    else if (mPosition == Button::SVP_RIGHT_BOTTOM)
    {
        if (mVertical)
        {
            int bottom = w->geometry().y() + w->geometry().height();
            QScrollBar *bar = verticalScrollBar();

            if (bar)
                bar->setSliderPosition(bottom);
        }
        else
        {
            int right = w->geometry().x() + w->geometry().width();
            QScrollBar *bar = horizontalScrollBar();

            if (bar)
                bar->setSliderPosition(right);
        }
    }
}

TQScrollArea::_ITEMS_T TQScrollArea::subViewItemToItem(PGSUBVIEWITEM_T& item)
{
    DECL_TRACER("TQScrollArea::subViewItemToItem(PGSUBVIEWITEM_T& item)");

    _ITEMS_T it;
    it.handle = item.handle;
    it.parent = item.parent;
    it.width = item.width;
    it.height = item.height;
    it.bgcolor = item.bgcolor;
    it.bounding = item.bounding;
    it.image = item.image;
    it.position = item.position;
    it.scrollbar = item.scrollbar;
    it.scrollbarOffset = item.scrollbarOffset;
    it.wrap = item.wrap;
    it.atoms = item.atoms;

    return it;
}

void TQScrollArea::_clearAllItems()
{
    DECL_TRACER("TQScrollArea::_clearAllItems()");

    if (mItems.empty())
        return;

    vector<_ITEMS_T>::iterator clIter;

    for (clIter = mItems.begin(); clIter != mItems.end(); ++clIter)
    {
        if (clIter->item)
        {
            if (mVertical)
            {
                if (mVLayout)
                    mVLayout->removeWidget(clIter->item);
            }
            else
            {
                if (mHLayout)
                    mHLayout->removeWidget(clIter->item);
            }

            clIter->item->close();
            clIter->item = nullptr;
        }
    }
}

void TQScrollArea::resetSlider(int position)
{
    DECL_TRACER("TQScrollArea::resetSlider(int position)");

    if (mActPosition <= 0)
        return;

    QScrollBar *sbar = nullptr;

    if (mVertical)
        sbar = verticalScrollBar();
    else
        sbar = horizontalScrollBar();

    if (sbar)
    {
        mOldActPosition = sbar->value();
        sbar->setSliderPosition(position);
    }
    else
        mOldActPosition = mActPosition;
}

/*****************************************************************************
 * Signals and overwritten functions start here
 *****************************************************************************/

void TQScrollArea::scrollContentsBy(int dx, int dy)
{
    DECL_TRACER("TQScrollArea::scrollContentsBy(int dx, int dy)");

    QScrollArea::scrollContentsBy(dx, dy);      // First let the original class do it's job.
    QScrollBar *sbar = nullptr;

    if (mVertical)
        sbar = verticalScrollBar();
    else
        sbar = horizontalScrollBar();

    if (sbar)
    {
        mActPosition = sbar->value();
        MSG_DEBUG("Actual slider position: " << mActPosition);

        if (mScrollbar && mScrollbarOffset > 0 && mActPosition < mScrollbarOffset)
        {
            sbar->setSliderPosition(mScrollbarOffset);
            mActPosition = sbar->value();
        }
    }
}

void TQScrollArea::mouseMoveEvent(QMouseEvent* event)
{
    DECL_TRACER("TQScrollArea::mouseMoveEvent(QMouseEvent* event)");

    mMousePress = false;
    mMouseScroll = true;
    mDoMouseEvent = false;

    if (mMousePressTimer && mMousePressTimer->isActive())
        mMousePressTimer->stop();

    int move = 0;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    MSG_DEBUG("Scroll event at " << event->pos().x() << "x" << event->pos().y() << ", old point at " << mOldPoint.x() << "x" << mOldPoint.y());
#else
    MSG_DEBUG("Scroll event at " << event->position().x() << "x" << event->position().y() << ", old point at " << mOldPoint.x() << "x" << mOldPoint.y());
#endif
    if (mVertical)
    {
        if (mOldPoint.y() != 0)
        {
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
            move = event->pos().y() - mOldPoint.y();
#else
            move = event->position().y() - mOldPoint.y();
#endif
            QScrollBar *bar = verticalScrollBar();

            if (bar)
            {
                int value = bar->value();
                value += (move * -1);
                bar->setValue(value);
            }
        }
    }
    else
    {
        if (mOldPoint.x() != 0)
        {
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
            move = event->pos().x() - mOldPoint.x();
#else
            move = event->position().x() - mOldPoint.x();
#endif
            QScrollBar *bar = horizontalScrollBar();

            if (bar)
            {
                int value = bar->value();
                int newValue = value + (move * -1);

                if (newValue >= 0 && newValue != value)
                    bar->setValue(newValue);
            }
        }
    }

#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    mOldPoint = event->pos();
#else
    mOldPoint = event->position();
#endif
}

void TQScrollArea::mousePressEvent(QMouseEvent* event)
{
    DECL_TRACER("TQScrollArea::mousePressEvent(QMouseEvent* event)");

    if (!event || mMouseScroll || event->button() != Qt::LeftButton)
        return;

    mMousePress = true;
    mOldPoint.setX(0.0);
    mOldPoint.setY(0.0);

    int x = 0, y = 0;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    x = event->pos().x();
    y = event->pos().y();
#else
    x = event->position().x();
    y = event->position().y();
#endif
    mLastMousePress.setX(x);
    mLastMousePress.setY(y);

    MSG_DEBUG("Mouse press event at " << x << " x " << y << " // " << event->globalX() << " x " << event->globalY());
    /*
        * Here we're starting a timer with 200 ms. If after this time the
        * mouse button is still pressed and no scroll event was detected,
        * then we've a real click.
        * In case of a real click the method mouseTimerEvent() will call a
        * signal to inform the parent about the click.
        */
    mClick = true;  // This means PRESSED state
    mMouseTmEventActive = true;
    mDoMouseEvent = true;
    QTimer::singleShot(200, this, &TQScrollArea::mouseTimerEvent);
}

void TQScrollArea::mouseReleaseEvent(QMouseEvent* event)
{
    DECL_TRACER("TQScrollArea::mouseReleaseEvent(QMouseEvent* event)");

    if (!event || event->button() != Qt::LeftButton)
        return;

    mDoMouseEvent = false;

    if (mMouseTmEventActive)
    {
        if (!mMouseScroll)
        {
            mClick = true;      // This means PRESSED state
            doMouseEvent();
            mClick = false;     // This means RELEASED state
            doMouseEvent();
        }
    }
    else if (!mMouseScroll && mClick)
    {
        mClick = false;         // This means RELEASED state
        doMouseEvent();
    }

    mMousePress = false;
    mMouseScroll = false;
    mOldPoint.setX(0.0);
    mOldPoint.setY(0.0);
}

void TQScrollArea::doMouseEvent()
{
    DECL_TRACER("TQScrollArea::doMouseEvent()");

    if (!mMousePress || mMouseScroll || !mMain)
        return;

    QWidget *w = nullptr;

    if (mVertical)
        w = mMain->childAt(mLastMousePress.x(), mActPosition + mLastMousePress.y());
    else
        w = mMain->childAt(mActPosition + mLastMousePress.x(), mLastMousePress.y());

    if (!w)
        return;

    QString obname = w->objectName();
    ulong handle = extractHandle(obname.toStdString());

    if (!handle)
        return;

    // We must make sure the found object is not marked as pass through.
    // Because of this we'll scan the items for the handle and if we
    // find that it is marked as pass through we must look for another
    // one on the same position. If there is none, the click is ignored.
    //
    // Find the object in our list
    vector<_ITEMS_T>::iterator iter;
    QRect rect;
    bool call = true;

    for (iter = mItems.begin(); iter != mItems.end(); ++iter)
    {
        if (iter->handle == handle)     // Handle found?
        {                               // Yes, then ...
            if (iter->bounding == "passThru")   // Item marked as pass through?
            {                                   // Yes, then start to search for another item
                rect = w->rect();
                call = false;
                // Walk through the childs to find another one on the
                // clicked position.
                QObjectList ol = mMain->children(); // Get list of all objects
                QList<QObject *>::iterator obiter;  // Define an iterator
                // Loop through all objects
                for (obiter = ol.begin(); obiter != ol.end(); ++obiter)
                {
                    QObject *object = *obiter;

                    if (object->objectName() != obname && object->objectName().startsWith("Label_"))    // Have we found a QLabel object?
                    {                                                                                   // Yes, then test it's position
                        QLabel *lb = dynamic_cast<QLabel *>(object);    // Cast the object to a QLabel

                        if (lb->rect().contains(mLastMousePress))       // Is the QLabel under the mouse coordinates?
                        {                                               // Yes, then select it.
                            ulong h = extractHandle(lb->objectName().toStdString());  // Get the handle

                            if (!h)
                                break;

                            handle = h;
                            // Reset the main loop
                            iter = mItems.begin();
                            break;
                        }
                    }
                }
            }
            else
            {
                call = true;
                break;
            }
        }
    }

    if (call)
    {
        MSG_DEBUG("Calling signal with handle " << (handle >> 16 & 0x0000ffff) << ":" << (handle & 0x0000ffff) << ": STATE=" << (mClick ? "PRESSED" : "RELEASED"));
        emit objectClicked(handle, mClick);
        mClick = false;
    }
}

void TQScrollArea::mouseTimerEvent()
{
    DECL_TRACER("TQScrollArea::mouseTimerEvent()");

    if (!mDoMouseEvent)
        return;

    mDoMouseEvent = false;

    if (mClick)         // Only if PRESSED
        doMouseEvent();

    mMouseTmEventActive = false;
}