diff --git a/kcm/src/declarative/qmlscreen.h b/kcm/src/declarative/qmlscreen.h --- a/kcm/src/declarative/qmlscreen.h +++ b/kcm/src/declarative/qmlscreen.h @@ -100,11 +100,14 @@ private: void qmlOutputMoved(QMLOutput *qmlOutput); void updateCornerOutputs(); + void setOutputScale(float scale); KScreen::ConfigPtr m_config; QHash m_outputMap; - int m_connectedOutputsCount = 0; - int m_enabledOutputsCount = 0; + QVector m_manuallyMovedOutputs; + int m_connectedOutputsCount; + int m_enabledOutputsCount; + float m_outputScale = 1.0 / 8.0; QMLOutput *m_leftmost = nullptr; QMLOutput *m_topmost = nullptr; diff --git a/kcm/src/declarative/qmlscreen.cpp b/kcm/src/declarative/qmlscreen.cpp --- a/kcm/src/declarative/qmlscreen.cpp +++ b/kcm/src/declarative/qmlscreen.cpp @@ -49,6 +49,7 @@ { qDeleteAll(m_outputMap); m_outputMap.clear(); + m_manuallyMovedOutputs.clear(); m_bottommost = m_leftmost = m_rightmost = m_topmost = nullptr; m_connectedOutputsCount = 0; m_enabledOutputsCount = 0; @@ -175,7 +176,7 @@ float QMLScreen::outputScale() const { - return 1.0 / 12.0; + return m_outputScale; } void QMLScreen::outputConnectedChanged() @@ -225,6 +226,8 @@ if (qmlOutput->isCloneMode()) { return; } + if (!m_manuallyMovedOutputs.contains(qmlOutput)) + m_manuallyMovedOutputs.append(qmlOutput); updateCornerOutputs(); @@ -304,52 +307,78 @@ } } +void QMLScreen::setOutputScale(float scale) +{ + if (qFuzzyCompare(scale, m_outputScale)) + return; + m_outputScale = scale; + emit outputScaleChanged(); +} + void QMLScreen::updateOutputsPlacement() { - QSizeF activeScreenSize; + if (width() <= 0) + return; + + QSizeF initialActiveScreenSize; Q_FOREACH (QQuickItem *item, childItems()) { QMLOutput *qmlOutput = qobject_cast(item); if (!qmlOutput->output()->isConnected() || !qmlOutput->output()->isEnabled()) { continue; } - if (qmlOutput->outputX() + qmlOutput->currentOutputWidth() > activeScreenSize.width()) { - activeScreenSize.setWidth(qmlOutput->outputX() + qmlOutput->currentOutputWidth()); + if (qmlOutput->outputX() + qmlOutput->currentOutputWidth() > initialActiveScreenSize.width()) { + initialActiveScreenSize.setWidth(qmlOutput->outputX() + qmlOutput->currentOutputWidth()); } - if (qmlOutput->outputY() + qmlOutput->currentOutputHeight() > activeScreenSize.height()) { - activeScreenSize.setHeight(qmlOutput->outputY() + qmlOutput->currentOutputHeight()); + if (qmlOutput->outputY() + qmlOutput->currentOutputHeight() > initialActiveScreenSize.height()) { + initialActiveScreenSize.setHeight(qmlOutput->outputY() + qmlOutput->currentOutputHeight()); } } - activeScreenSize *= outputScale(); - - const QPointF offset((width() - activeScreenSize.width()) / 2.0, - (height() - activeScreenSize.height()) / 2.0); - + auto initialScale = outputScale(); + auto scale = initialScale; qreal lastX = -1.0; - qreal lastY = -1.0; - Q_FOREACH (QQuickItem *item, childItems()) { - QMLOutput *qmlOutput = qobject_cast(item); - if (!qmlOutput->output()->isConnected() || !qmlOutput->output()->isEnabled()) { - continue; - } - - qmlOutput->blockSignals(true); - qmlOutput->setPosition(QPointF(offset.x() + (qmlOutput->outputX() * outputScale()), - offset.y() + (qmlOutput->outputY() * outputScale()))); - lastX = qMax(lastX, qmlOutput->position().x() + qmlOutput->size().width()); - lastY = qMax(lastY, qmlOutput->position().y()); - qmlOutput->blockSignals(false); - } + 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(item); + if (!qmlOutput->output()->isConnected() || !qmlOutput->output()->isEnabled() || + m_manuallyMovedOutputs.contains(qmlOutput)) { + continue; + } - Q_FOREACH (QQuickItem *item, childItems()) { - QMLOutput *qmlOutput = qobject_cast(item); - if (qmlOutput->output()->isConnected() && !qmlOutput->output()->isEnabled()) { qmlOutput->blockSignals(true); - qmlOutput->setPosition(QPointF(lastX, lastY)); - lastX += qmlOutput->size().width(); + qmlOutput->setPosition(QPointF(offset.x() + (qmlOutput->outputX() * scale), + offset.y() + (qmlOutput->outputY() * scale))); + lastX = qMax(lastX, qmlOutput->position().x() + qmlOutput->size().width() / initialScale * scale); + lastY = qMax(lastY, qmlOutput->position().y()); qmlOutput->blockSignals(false); } - } + + Q_FOREACH (QQuickItem *item, childItems()) { + QMLOutput *qmlOutput = qobject_cast(item); + if (qmlOutput->output()->isConnected() && !qmlOutput->output()->isEnabled() && + !m_manuallyMovedOutputs.contains(qmlOutput)) { + qmlOutput->blockSignals(true); + qmlOutput->setPosition(QPointF(lastX, lastY)); + lastX += qmlOutput->size().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); + }); }