/*
    Copyright (C) 2012  Dan Vratil <dvratil@redhat.com>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "qmlscreen.h"
#include "qmloutputcomponent.h"
#include "qmloutput.h"

#include <KF5/KScreen/kscreen/output.h>
#include <KF5/KScreen/kscreen/config.h>

#include <QTimer>
#include <sys/socket.h>
#include <QtMath>

Q_DECLARE_METATYPE(KScreen::OutputPtr)

QMLScreen::QMLScreen(QQuickItem *parent) :
    QQuickItem(parent)
{
    connect(this, &QMLScreen::widthChanged, this, &QMLScreen::viewSizeChanged);
    connect(this, &QMLScreen::heightChanged, this, &QMLScreen::viewSizeChanged);
}

QMLScreen::~QMLScreen()
{
    qDeleteAll(m_outputMap);
    m_outputMap.clear();
}

KScreen::ConfigPtr QMLScreen::config() const
{
    return m_config;
}

void QMLScreen::setConfig(const KScreen::ConfigPtr &config)
{
    qDeleteAll(m_outputMap);
    m_outputMap.clear();
    m_manuallyMovedOutputs.clear();
    m_connectedOutputsCount = 0;
    m_enabledOutputsCount = 0;

    if (m_config) {
        m_config->disconnect(this);
    }

    m_config = config;
    connect(m_config.data(), &KScreen::Config::outputAdded,
            this, [this](const KScreen::OutputPtr &output) {
        QTimer::singleShot(1000, this, [=]{
            addOutput(output);
            updateOutputsPlacement();
        });
    });
    connect(m_config.data(), &KScreen::Config::outputRemoved,
            this, &QMLScreen::removeOutput);

    for (const KScreen::OutputPtr &output : m_config->outputs()) {
        addOutput(output);
    }

    updateOutputsPlacement();

    for (QMLOutput *qmlOutput : m_outputMap) {
        if (qmlOutput->output()->isConnected() && qmlOutput->output()->isEnabled()) {
            qmlOutput->dockToNeighbours();
        }
    }
}

void QMLScreen::addOutput(const KScreen::OutputPtr &output)
{
    QMLOutputComponent comp(qmlEngine(this), this);

    QMLOutput *qmloutput = comp.createForOutput(output);
    if (!qmloutput) {
        qWarning() << "Failed to create QMLOutput";
        return;
    }

    m_outputMap.insert(output, qmloutput);

    qmloutput->setParentItem(this);
    qmloutput->setZ(m_outputMap.count());

    connect(output.data(), &KScreen::Output::isConnectedChanged,
            this, &QMLScreen::outputConnectedChanged);
    connect(output.data(), &KScreen::Output::isEnabledChanged,
            this, &QMLScreen::outputEnabledChanged);
    connect(output.data(), &KScreen::Output::posChanged,
            this, &QMLScreen::outputPositionChanged);
    connect(qmloutput, &QMLOutput::yChanged,
            [this, qmloutput]() {
        qmlOutputMoved(qmloutput);
    });
    connect(qmloutput, &QMLOutput::xChanged,
            [this, qmloutput]() {
        qmlOutputMoved(qmloutput);
    });

    // 在这里点击上面小屏幕
    connect(qmloutput, SIGNAL(clicked()),
            this, SLOT(setActiveOutput()));

    connect(qmloutput, SIGNAL(clicked()),
            this, SLOT(getClickedPos()));

    connect(qmloutput, SIGNAL(mouseReleased(bool)),
            this, SLOT(setScreenPos(bool)));

    connect(qmloutput, SIGNAL(rotationChanged(bool)),
            this, SLOT(setScreenPos(bool)));

    connect(qmloutput, SIGNAL(widthChanged(bool)),
            this, SLOT(setScreenPos(bool)));

    connect(qmloutput, SIGNAL(heightChanged(bool)),
            this, SLOT(setScreenPos(bool)));

    connect(qmloutput, &QMLOutput::visibleChanged, this, [=](){
        viewSizeChanged();
    });

    qmloutput->updateRootProperties();
    viewSizeChanged();
}

void QMLScreen::removeOutput(int outputId)
{
    for (const KScreen::OutputPtr &output : m_outputMap.keys()) {
        if (output->id() == outputId) {
            QMLOutput *qmlOutput = m_outputMap.take(output);
            qmlOutput->setParentItem(nullptr);
            qmlOutput->setParent(nullptr);
            // TODO:bug51346
            // qmlOutput->deleteLater();
            return;
        }
    }
}

int QMLScreen::connectedOutputsCount() const
{
    return m_connectedOutputsCount;
}

int QMLScreen::enabledOutputsCount() const
{
    return m_enabledOutputsCount;
}

QMLOutput *QMLScreen::primaryOutput() const
{
    Q_FOREACH (QMLOutput *qmlOutput, m_outputMap) {
        if (qmlOutput->output()->isPrimary()) {
            return qmlOutput;
        }
    }

    return nullptr;
}

QList<QMLOutput *> QMLScreen::outputs() const
{
    return m_outputMap.values();
}

void QMLScreen::getClickedPos()
{
    leftPosList.clear();
    // 应该判断所有显示器的坐标是否变化，移动A屏幕可能只会改变A与B屏幕的相对位置，A本身的屏幕位置可能不变(比如(0, 1680))
    Q_FOREACH (QMLOutput *qmlOutput, m_outputMap) {
        if (qmlOutput->output()->isConnected()) {
            leftPosList.append(qmlOutput->position().x());
            leftPosList.append(qmlOutput->position().y());
        }
    }
}

void QMLScreen::setActiveOutput(QMLOutput *output)
{
    Q_FOREACH (QMLOutput *qmlOutput, m_outputMap) {
        if (qmlOutput->z() > output->z()) {
            qmlOutput->setZ(qmlOutput->z() - 1);
        }
    }

    output->setZ(m_outputMap.count());
    // 中屏幕
    output->setFocus(true);
    Q_EMIT focusedOutputChanged(output);
}

void QMLScreen::setScreenCenterPos()
{
    // 组成最大矩形四个边的位置，分别对应左上(1)，右下(2)的xy坐标值
    qreal localX1 = -1, localX2 = -1, localY1 = -1, localY2 = -1;
    qreal mX1 = 0, mY1 = 0, mX2 = 0, mY2 = 0; // 矩形中点坐标
    qreal moveX = 0, moveY = 0;// 移动的值
    bool firstFlag = true;
    Q_FOREACH (QMLOutput *qmlOutput, m_outputMap) {
        if (qmlOutput->output()->isConnected() && qmlOutput->isVisible()) {
            if (firstFlag == true || localX1 > qmlOutput->x()) {
                localX1 = qmlOutput->x();
            }
            if (firstFlag == true || localX2 < qmlOutput->x() + qmlOutput->width()) {
                localX2 = qmlOutput->x() + qmlOutput->width();
            }
            if (firstFlag == true || localY1 > qmlOutput->y()) {
                localY1 = qmlOutput->y();
            }
            if (firstFlag == true || localY2 < qmlOutput->y() + qmlOutput->height()) {
                localY2 = qmlOutput->y() + qmlOutput->height();
            }
            firstFlag = false;
        }
    }

    mX1 = localX1 + (localX2-localX1)/2;
    mY1 = localY1 + (localY2-localY1)/2;

    mX2 = width()/2;
    mY2 = height()/2;

    moveX = mX2 - mX1;
    moveY = mY2 - mY1;

    Q_FOREACH (QMLOutput *qmlOutput, m_outputMap) {
        if (qmlOutput->output()->isConnected() && qmlOutput->isVisible()) {
            qDebug() << Q_FUNC_INFO << " before set position " << qmlOutput->output()->name() << qmlOutput->position() << qmlOutput->size();
            qmlOutput->blockSignals(true);
            qmlOutput->setX(qmlOutput->x() + moveX);
            qmlOutput->setY(qmlOutput->y() + moveY);
            qmlOutput->blockSignals(false);
            qDebug() << Q_FUNC_INFO << " after set position " << qmlOutput->output()->name() << qmlOutput->position() << qmlOutput->size();
        }
    }
}

struct RectangleDistance QMLScreen::calculateRectangleDistance(QMLOutput *qmlOutput1, QMLOutput *qmlOutput2)
{
    struct RectangleDistance res;
    const float x1 = qmlOutput1->x();
    const float y1 = qmlOutput1->y();
    const float w1 = qmlOutput1->width();
    const float h1 = qmlOutput1->height();
    const float x2 = qmlOutput2->x();
    const float y2 = qmlOutput2->y();
    const float w2 = qmlOutput2->width();
    const float h2 = qmlOutput2->height();

    QPointF C1, C2;
    C1.setX(x1 + (w1 / 2));
    C1.setY(y1 + (h1 / 2));
    C2.setX(x2 + (w2 / 2));
    C2.setY(y2 + (h2 / 2));

    // 分别计算两矩形中心点在X轴和Y轴方向的距离
    float Dx, Dy;
    Dx = qFabs(C2.x() - C1.x());
    Dy = qFabs(C2.y() - C1.y());
    //本身就是紧邻在一起的
    if ((fabs(Dx - (w1 + w2)/2) <= 0.001) && (Dy - (h1 + h2)/2 <= 0.001) && (Dy > 0.001)) {
        res.m_distance = 0.0;
        res.m_type = Recent;
    } else if ((fabs(Dy - (h1 + h2)/2) <= 0.001) && (Dx - (w1 + w2)/2 <= 0.001) && (Dx > 0.001)) {
        res.m_distance = 0.0;
        res.m_type = Recent;
    }
    //两矩形不相交，在X轴方向有部分重合的两个矩形，最小距离是上矩形的下边线与下矩形的上边线之间的距离
    else if ((Dx < ((w1 + w2)/2)) && (Dy >= ((h1 + h2) /2))) {
        res.m_distance = Dy - ((h1 + h2)/2);
        res.m_type = Vertical;
    }
    //两矩形不相交，在Y轴方向有部分重合的两个矩形，最小距离是左矩形的右边线与右矩形的左边线之间的距离
    else if ((Dx >= ((w1 + w2)/2)) && (Dy < ((h1 + h2) /2))) {
        res.m_distance = Dx - ((w1 + w2)/2);
        res.m_type = Horizontal;
    }
    //两矩形不相交，在X轴和Y轴方向无重合的两个矩形，最小距离是距离最近的两个顶点之间的距离，
    else if ((Dx >= ((w1 + w2)/2)) && (Dy >= ((h1 + h2) /2))) {
        float delta_x = Dx - ((w1 + w2)/2);
        float delta_y = Dy - ((h1 + h2)/2);
        res.m_distance = qSqrt(delta_x * delta_x  + delta_y * delta_y);
        res.m_type = None;
    }
    //两矩形相交，最小距离为负值
    else {
        float distanceX = qMin(x1 + w1, x2 + w2) - qMax(x1, x2);
        float distanceY = qMin(y1 + h1, y2 + h2) - qMax(y1, y2);
        if (distanceX < 0 || distanceY < 0) {
            qWarning()<<"calculateRectangleDistance error:"<<distanceX<<","<<distanceY;
        }
        // 两矩形完全重叠
        if (distanceX == x1 && x1 == x2 && distanceY == y1 && y1 == y2) {
            res.m_distance = distanceY;
            res.m_type = Vertical;
        // 重叠距离为某个矩形的高度减去宽度，多发生于旋转
        } else if (qFabs(distanceX - qFabs(h1 - w1)) < 0.001 || qFabs(distanceX - qFabs(h2 - w2)) < 0.001) {
            res.m_distance = distanceX;
            res.m_type = Horizontal;
        // 重叠距离为某个矩形的宽度减去高度，多发生于旋转
        } else if (qFabs(distanceY - qFabs(w1 - h1)) < 0.001 || qFabs(distanceY - qFabs(w2 - h2)) < 0.001) {
            res.m_distance = distanceY;
            res.m_type = Vertical;
        // 重叠距离等于某个矩形的宽，则认为是垂直的
        } else if (qFabs(distanceX - w1) < 0.001 || qFabs(distanceX - w2) < 0.001) {
            res.m_distance = distanceY;
            res.m_type = Vertical;
        // 重叠距离等于某个矩形的高，则认为是水平的
        } else if (qFabs(distanceY - h1) < 0.001 || qFabs(distanceY - h2) < 0.001) {
            res.m_distance = distanceX;
            res.m_type = Horizontal;
        // 距离在水平最小
        } else if (distanceX <= distanceY) {
            res.m_distance = distanceX;
            res.m_type = Horizontal;
        // 其它情况
        } else {
            res.m_distance = distanceY;
            res.m_type = Vertical;
        }
    }
    return res;
}

void QMLScreen::resetOutputPos(QMLOutput *output, type m_type, QMLOutput *outputRef)
{
    if (m_type == Horizontal) {
        output->setX(outputRef->x() + outputRef->width());
    } else if (m_type == Vertical) {
        if (output->y() > outputRef->y()) {
            output->setY(outputRef->y() + outputRef->height());
        } else {
            output->setY(outputRef->y() - output->height());
        }
    } else if (m_type == None) {
        output->setX(outputRef->x() + outputRef->width());
        if (output->y() > outputRef->y()) {
            output->setY(outputRef->y() + outputRef->height());
        } else {
            output->setY(outputRef->y() - output->height());
        }
    } else if (m_type == Recent) {
        return;
    }
}

void QMLScreen::setScreenPosMulti(int connectScreenNum) {
    int outputOrder[connectScreenNum];
    float output_x[connectScreenNum];
    float distance_d[connectScreenNum][connectScreenNum];
    struct RectangleDistance distance_r[connectScreenNum][connectScreenNum];
    QMLOutput *allConnectedOutput[connectScreenNum];

    int mm = 0;
    Q_FOREACH (QMLOutput *qmlOutput, m_outputMap) {
        if (qmlOutput->output()->isConnected()) {
            allConnectedOutput[mm] = qmlOutput;
            output_x[mm] = qmlOutput->x();
            mm++;
        }
    }
    //横坐标最小(最左边)的显示器为参考,找到该显示器
    outputOrder[0] = std::min_element(output_x, output_x + connectScreenNum) - output_x;
    mm = 0;
    Q_FOREACH (QMLOutput *qmlOutput, m_outputMap) {
        if (!qmlOutput->output()->isConnected()) {
            continue;
        }
        if (qmlOutput != allConnectedOutput[outputOrder[0]] && qmlOutput->output()->isConnected()) {
           struct RectangleDistance m_res =  calculateRectangleDistance(allConnectedOutput[outputOrder[0]], qmlOutput);
           distance_r[0][mm] = m_res;
           distance_d[0][mm] = m_res.m_distance;
        } else if (qmlOutput == allConnectedOutput[outputOrder[0]]) {
           distance_d[0][mm] = 1000000.0;
        }
        mm++;
    }

    float recentData = -1;
    outputOrder[1] = std::min_element(distance_d[0], distance_d[0] + connectScreenNum) - distance_d[0];
    recentData = *std::min_element(distance_d[0], distance_d[0] + connectScreenNum);
    //紧邻的，不需要做处理
    if (fabs(recentData) <= 0.0001) {
    //非紧邻，需要移至紧邻
    } else {
        resetOutputPos(allConnectedOutput[outputOrder[1]], distance_r[0][outputOrder[1]].m_type, allConnectedOutput[outputOrder[0]]);
    }
    //判断剩下的离之前两个哪个矩形更近
    for (mm = 0; mm < connectScreenNum; mm++) {
        if (mm != outputOrder[1] && mm != outputOrder[0]) {
            //计算与第二个确定矩形的距离
            struct RectangleDistance m_res =  calculateRectangleDistance(allConnectedOutput[outputOrder[1]], allConnectedOutput[mm]);
            distance_d[1][mm] = m_res.m_distance;
            distance_r[1][mm] = m_res;
        }
    }

    if (connectScreenNum == 2) {

    } else if (connectScreenNum == 3) {
        outputOrder[2] = 3 - outputOrder[1] - outputOrder[0];
        if (distance_d[0][outputOrder[2]] < distance_d[1][outputOrder[2]]) {
            resetOutputPos(allConnectedOutput[outputOrder[2]], distance_r[0][outputOrder[2]].m_type, allConnectedOutput[outputOrder[0]]);
        } else {
            resetOutputPos(allConnectedOutput[outputOrder[2]], distance_r[1][outputOrder[2]].m_type, allConnectedOutput[outputOrder[1]]);
        }
    } else if (connectScreenNum == 4) {
        for (mm = 0; mm < connectScreenNum; mm++) {
            if (mm != outputOrder[1] && mm != outputOrder[0]) {
                outputOrder[2] = mm;
                outputOrder[3] = 6 - outputOrder[0] - outputOrder[1] - outputOrder[2];
                break;
            }
        }
        float m_distance[4] = { distance_d[0][outputOrder[2]],distance_d[1][outputOrder[2]],
                                distance_d[0][outputOrder[3]],distance_d[1][outputOrder[3]] };

        int tempNum;
        //outputOrder[2]就是最近的
        if ((std::min_element(m_distance, m_distance + 4) - m_distance) < 2) {
        //lastNum是最近的
        } else {
            tempNum = outputOrder[2];
            outputOrder[2] = outputOrder[3];
            outputOrder[3] = tempNum;
        }
        //离第一个最近
        if (distance_d[0][outputOrder[2]] < distance_d[1][outputOrder[2]]) {
            resetOutputPos(allConnectedOutput[outputOrder[2]],distance_r[0][outputOrder[2]].m_type,allConnectedOutput[outputOrder[0]]);
        //离第二个最近    
        } else {
            resetOutputPos(allConnectedOutput[outputOrder[2]],distance_r[1][outputOrder[2]].m_type,allConnectedOutput[outputOrder[1]]);
        }
        distance_r[2][0] = calculateRectangleDistance(allConnectedOutput[outputOrder[0]], allConnectedOutput[outputOrder[3]]);
        distance_r[2][1] = calculateRectangleDistance(allConnectedOutput[outputOrder[1]], allConnectedOutput[outputOrder[3]]);
        distance_r[2][2] = calculateRectangleDistance(allConnectedOutput[outputOrder[2]], allConnectedOutput[outputOrder[3]]);
        distance_d[2][0] = distance_r[2][0].m_distance;
        distance_d[2][1] = distance_r[2][1].m_distance;
        distance_d[2][2] = distance_r[2][2].m_distance;
        tempNum = std::min_element(distance_d[2], distance_d[2] + 3) - distance_d[2];
        int tempNum2 = tempNum;
        if (tempNum == 0) {
            tempNum = outputOrder[0];
        } else if (tempNum == 1) {
            tempNum = outputOrder[1];
        } else if (tempNum == 2) {
            tempNum = outputOrder[2];
        }
        resetOutputPos(allConnectedOutput[outputOrder[3]],distance_r[2][tempNum2].m_type,allConnectedOutput[tempNum]);
    }
}

void QMLScreen::setScreenPos(QMLOutput *output, bool isReleased)
{
    // 镜像模式下跳过屏幕旋转处理
    if (output->isCloneMode()) {
        return;
    }
    output->setSize(QSizeF(output->property("saveWidth").toDouble(), output->property("saveHeight").toDouble()));
    float x1 = 0, y1 = 0;
    float width1 = 0, height1 = 0;
    float x2 = 0, y2 = 0;
    float width2 = 0, height2 = 0;

    x1 = output->x();
    y1 = output->y();
    width1 = output->width();
    height1 = output->height();

    int connectedScreen = 0;

    QMLOutput *other = nullptr;
    Q_FOREACH (QMLOutput *qmlOutput, m_outputMap) {
        if (qmlOutput->output()->isConnected()) {
            connectedScreen++;
        }
        if (qmlOutput != output && qmlOutput->output()->isConnected()) {
            qmlOutput->setSize(QSizeF(qmlOutput->property("saveWidth").toDouble(), qmlOutput->property("saveHeight").toDouble()));
            other = qmlOutput;
            x2 = other->x();
            y2 = other->y();
            width2 = other->width();
            height2 = other->height();
        }
    }

    if (connectedScreen == 2 || connectedScreen == 3 || connectedScreen == 4) {
        setScreenPosMulti(connectedScreen);
    } else {
        // 坐标为负的情况，bug#76350
        if (x1 < 0 || y1 < 0 || x2 < 0 || y2 < 0) {
            if (isReleased)
                setScreenCenterPos();
            return;
        }

        if (connectedScreen < 2) {
            setScreenCenterPos();
            return;
        }

        if (!((x1 + width1 == x2)
              || (y1 == y2 + height2)
              || (x1 == x2 + width2)
              || (y1 + height1 == y2))) {
            if (x1 + width1 < x2) {
                output->setX(x2 - width1);
                output->setY(y2);
            } else if (y1 > y2 + height2) {
                output->setX(x2);
                output->setY(y2 + height2);
            } else if (x1 > x2 + width2) {
                output->setX(x2 + width2);
                output->setY(y2);
            } else if (y1 + height1 < y2) {
                output->setX(x2);
                output->setY(y2 - height1);
            }

            // 矩形是否相交
            if (!(x1 + width1 <= x2 || x2 + width2 <= x1
                  || y1 >= y2 +height2 || y2 >= y1 + height1)
                    && (x1 != x2 || y1 != y2) && other != nullptr
                && other->output()->isConnected()) {
                if ((x1 + width1 > x2) && (x1 < x2)) {
                    output->setX(x2 - width1);
                } else if ((x1 < x2 + width2) && (x1 + width1 > x2 + width2)) {
                    output->setX(x2 + width2);
                } else if ((y1 + height() > y2) && (y1 < y2 + height2)) {
                    output->setY(y2 - height1);
                } else if ((y1 < y2  + height2) && (y1 + height1 > y2 + height2)) {
                    output->setY(y2 + height2);
                }
            }
        }
    }
    setScreenCenterPos();
    rightPosList.clear();
    Q_FOREACH (QMLOutput *qmlOutput, m_outputMap) {
        if (qmlOutput->output()->isConnected()) {
            rightPosList.append(qmlOutput->position().x());
            rightPosList.append(qmlOutput->position().y());
        }
    }
    if (isReleased) {
        if (leftPosList.size() != rightPosList.size()) {
            Q_EMIT released();
        } else {
            for (int i = 0; i < leftPosList.size(); ++i) {
                if (qFabs(leftPosList.at(i) - rightPosList.at(i)) > 0.001) {
                    Q_EMIT released();
                    break;
                }
            }
        }
    }
    return;
}

void QMLScreen::setActiveOutputByCombox(int screenId)
{
    QHash<KScreen::OutputPtr, QMLOutput *>::const_iterator it = m_outputMap.constBegin();
    while (it != m_outputMap.constEnd()) {
        if (screenId == it.key()->id()) {
            setActiveOutput(it.value());
            return;
        }
        it++;
    }
}

QSize QMLScreen::maxScreenSize() const
{
    return m_config->screen()->maxSize();
}

float QMLScreen::outputScale() const
{
    return m_outputScale;
}

void QMLScreen::outputConnectedChanged()
{
    int connectedCount = 0;

    Q_FOREACH (const KScreen::OutputPtr &output, m_outputMap.keys()) {
        if (output->isConnected()) {
            ++connectedCount;
        }
    }

    if (connectedCount != m_connectedOutputsCount) {
        m_connectedOutputsCount = connectedCount;
        Q_EMIT connectedOutputsCountChanged();
        updateOutputsPlacement();
    }
}

void QMLScreen::outputEnabledChanged()
{
    const KScreen::OutputPtr output(qobject_cast<KScreen::Output *>(sender()), [](void *){
        });
    if (output->isEnabled()) {
        // bug#68442
        // updateOutputsPlacement();
    }
    int enabledCount = 0;

    Q_FOREACH (const KScreen::OutputPtr &output, m_outputMap.keys()) {
        if (output->isEnabled()) {
            ++enabledCount;
        }
    }

    if (enabledCount == m_enabledOutputsCount) {
        m_enabledOutputsCount = enabledCount;
        Q_EMIT enabledOutputsCountChanged();
    }
}

void QMLScreen::outputPositionChanged()
{
    /* TODO: Reposition the QMLOutputs */
}

void QMLScreen::qmlOutputMoved(QMLOutput *qmlOutput)
{
    if (qmlOutput->isCloneMode()) {
        return;
    }
    if (qFabs(qmlOutput->property("saveWidth").toDouble() - qmlOutput->width()) > 1.0|| qFabs(qmlOutput->property("saveHeight").toDouble() - qmlOutput->height()) > 1.0) {
        return;
    }

    if (!m_manuallyMovedOutputs.contains(qmlOutput))
        m_manuallyMovedOutputs.append(qmlOutput);

    updateCornerOutputs();

    Q_FOREACH (QMLOutput *m_qmlOutput, m_outputMap) {
        if (!m_qmlOutput->output()->isConnected() || !m_qmlOutput->output()->isEnabled()) {
            continue;
        }

        int x = qRound((m_qmlOutput->x() - leftX) / outputScale());
        int y = qRound((m_qmlOutput->y() - topY) / outputScale());
        m_qmlOutput->setOutputX(x);
        m_qmlOutput->setOutputY(y);
    }
}

void QMLScreen::viewSizeChanged()
{
    //TO fix bug#85240
//    updateOutputsPlacement();
    QTimer::singleShot(0,this,[=]{
        setScreenCenterPos();
    });
}

void QMLScreen::updateCornerOutputs()
{
    leftX = -1.0;
    topY = -1.0;

    Q_FOREACH (QMLOutput *output, m_outputMap) {
        if (!output->output()->isConnected() || !output->output()->isEnabled()) {
            continue;
        }

        if (leftX < 0 || leftX > output->x()) {
            leftX = output->x();
        }

        if (topY < 0 || topY > output->y()) {
            topY = output->y();
        }
    }
}

void QMLScreen::setOutputScale(float scale)
{
    if (qFuzzyCompare(scale, m_outputScale))
        return;
    m_outputScale = scale;
    emit outputScaleChanged();
}

// 画坐标
void QMLScreen::updateOutputsPlacement()
{
    if (width() <= 0)
        return;

    QSizeF initialActiveScreenSize;

    Q_FOREACH (QQuickItem *item, childItems()) {
        QMLOutput *qmlOutput = qobject_cast<QMLOutput *>(item);
        if (!qmlOutput->output()->isConnected() || !qmlOutput->output()->isEnabled()) {
            continue;
        }

        if (qmlOutput->outputX() + qmlOutput->currentOutputWidth()
            > initialActiveScreenSize.width()) {
            initialActiveScreenSize.setWidth(qmlOutput->outputX()
                                             + qmlOutput->currentOutputWidth());
        }
        if (qmlOutput->outputY() + qmlOutput->currentOutputHeight()
            > initialActiveScreenSize.height()) {
            initialActiveScreenSize.setHeight(
                qmlOutput->outputY() + qmlOutput->currentOutputHeight());
        }
    }

    auto initialScale = outputScale();

    auto scale = initialScale;
    qreal lastX = -1.0;
    do {
        auto activeScreenSize = initialActiveScreenSize * scale;

        const QPointF offset((width() - activeScreenSize.width()) / 2.0,
                             (height() - activeScreenSize.height()) / 2.0);

        lastX = -1.0;
        qreal lastY = -1.0;
        Q_FOREACH (QQuickItem *item, childItems()) {
            QMLOutput *qmlOutput = qobject_cast<QMLOutput *>(item);
            if (!qmlOutput->output()->isConnected() || !qmlOutput->output()->isEnabled()
                    || m_manuallyMovedOutputs.contains(qmlOutput)) {
                continue;
            }

            qmlOutput->blockSignals(true);
            qmlOutput->setPosition(QPointF(offset.x() + (qmlOutput->outputX() * scale),
                                           offset.y() + (qmlOutput->outputY() * scale)));
            lastX = qMax(lastX,
                         qmlOutput->position().x() + qmlOutput->width() / initialScale * scale);
            lastY = qMax(lastY, qmlOutput->position().y());
            qmlOutput->blockSignals(false);
        }

        Q_FOREACH (QQuickItem *item, childItems()) {
            QMLOutput *qmlOutput = qobject_cast<QMLOutput *>(item);
            if (qmlOutput->output()->isConnected() && !qmlOutput->output()->isEnabled()
                && !m_manuallyMovedOutputs.contains(qmlOutput)) {
                qmlOutput->blockSignals(true);
                qmlOutput->setPosition(QPointF(lastX, lastY));
                lastX += qmlOutput->width() / initialScale * scale;
                qmlOutput->blockSignals(false);
            }
        }
        // calculate the scale dynamically, so all screens fit to the dialog
        if (lastX > width()) {
            scale *= 0.8;
        }
    } while (lastX > width());

    // Use a timer to avoid binding loop on width()
    QTimer::singleShot(0, this, [scale, this] {
        setOutputScale(scale);
    });
}
