diff --git a/components/mobileshell/qml/navigationpanel/NavigationPanel.qml b/components/mobileshell/qml/navigationpanel/NavigationPanel.qml index cb00ad5e..d69d8488 100644 --- a/components/mobileshell/qml/navigationpanel/NavigationPanel.qml +++ b/components/mobileshell/qml/navigationpanel/NavigationPanel.qml @@ -54,6 +54,21 @@ Item { color: root.backgroundColor } + NavigationPanelButton { + id: leftCornerButton + visible: root.leftCornerAction.visible + Kirigami.Theme.colorSet: root.foregroundColorGroup + Kirigami.Theme.inherit: false + enabled: root.leftCornerAction.enabled + iconSizeFactor: root.leftCornerAction.iconSizeFactor + iconSource: root.leftCornerAction.iconSource + onClicked: { + if (enabled) { + root.leftCornerAction.triggered(); + } + } + } + // button row (anchors provided by state) NavigationPanelButton { id: leftButton @@ -166,6 +181,18 @@ Item { height: Kirigami.Units.gridUnit * 2 width: icons.width } + AnchorChanges { + target: leftCornerButton + anchors { + horizontalCenter: parent.horizontalCenter + bottom: parent.bottom + } + } + PropertyChanges { + target: leftCornerButton + height: Kirigami.Units.gridUnit * 2 + width: icons.width + } }, State { name: "horizontal" when: !root.isVertical @@ -214,6 +241,18 @@ Item { height: parent.height width: Kirigami.Units.gridUnit * 2 } + AnchorChanges { + target: leftCornerButton + anchors { + verticalCenter: parent.verticalCenter + left: parent.left + } + } + PropertyChanges { + target: leftCornerButton + height: parent.height + width: Kirigami.Units.gridUnit * 2 + } } ] } diff --git a/containments/taskpanel/CMakeLists.txt b/containments/taskpanel/CMakeLists.txt index 499a431e..5990f446 100644 --- a/containments/taskpanel/CMakeLists.txt +++ b/containments/taskpanel/CMakeLists.txt @@ -10,7 +10,9 @@ target_link_libraries(org.kde.plasma.mobile.taskpanel Qt::DBus Qt::Qml Qt::Quick + Qt::Sensors Plasma::Plasma + KF6::Screen ) diff --git a/containments/taskpanel/package/contents/ui/NavigationPanelComponent.qml b/containments/taskpanel/package/contents/ui/NavigationPanelComponent.qml index 2280d343..d7aff6e1 100644 --- a/containments/taskpanel/package/contents/ui/NavigationPanelComponent.qml +++ b/containments/taskpanel/package/contents/ui/NavigationPanelComponent.qml @@ -102,6 +102,18 @@ MobileShell.NavigationPanel { } } + leftCornerAction: MobileShell.NavigationPanelAction { + id: rotationAction + visible: Plasmoid.showRotationButton + enabled: true + iconSource: "rotation-allowed-symbolic" + iconSizeFactor: 0.75 + + onTriggered: { + Plasmoid.rotateToSuggestedRotation(); + } + } + rightCornerAction: MobileShell.NavigationPanelAction { id: keyboardToggleAction visible: ShellSettings.Settings.alwaysShowKeyboardToggleOnNavigationPanel || diff --git a/containments/taskpanel/taskpanel.cpp b/containments/taskpanel/taskpanel.cpp index 7d7511c9..e99d2448 100644 --- a/containments/taskpanel/taskpanel.cpp +++ b/containments/taskpanel/taskpanel.cpp @@ -11,12 +11,54 @@ #include #include +#include +#include +#include +#include + // register type for Keyboards.KWinVirtualKeyboard.forceActivate(); Q_DECLARE_METATYPE(QDBusPendingReply<>) +KScreen::Output::Rotation mapReadingOrientation(QOrientationReading::Orientation orientation) +{ + switch (orientation) { + case QOrientationReading::Orientation::TopUp: + return KScreen::Output::Rotation::None; + case QOrientationReading::Orientation::TopDown: + return KScreen::Output::Rotation::Inverted; + case QOrientationReading::Orientation::LeftUp: + return KScreen::Output::Rotation::Left; + case QOrientationReading::Orientation::RightUp: + return KScreen::Output::Rotation::Right; + case QOrientationReading::Orientation::FaceUp: + case QOrientationReading::Orientation::FaceDown: + case QOrientationReading::Orientation::Undefined: + return KScreen::Output::Rotation::None; + } + return KScreen::Output::Rotation::None; +} + TaskPanel::TaskPanel(QObject *parent, const KPluginMetaData &data, const QVariantList &args) : Plasma::Containment(parent, data, args) + , m_sensor{new QOrientationSensor(this)} { + connect(new KScreen::GetConfigOperation(), &KScreen::GetConfigOperation::finished, this, [this](auto *op) { + m_config = qobject_cast(op)->config(); + KScreen::ConfigMonitor::instance()->addConfig(m_config); + + // update all screens with event connect + for (KScreen::OutputPtr output : m_config->outputs()) { + connect(output.data(), &KScreen::Output::autoRotatePolicyChanged, this, &TaskPanel::updateShowRotationButton); + } + + // listen to all new screens and connect + connect(m_config.data(), &KScreen::Config::outputAdded, this, [this](const auto &output) { + connect(output.data(), &KScreen::Output::autoRotatePolicyChanged, this, &TaskPanel::updateShowRotationButton); + }); + }); + + connect(m_sensor, &QOrientationSensor::readingChanged, this, &TaskPanel::updateShowRotationButton); + m_sensor->start(); } void TaskPanel::triggerTaskSwitcher() const @@ -28,6 +70,79 @@ void TaskPanel::triggerTaskSwitcher() const QDBusConnection::sessionBus().send(message); } +void TaskPanel::rotateToSuggestedRotation() +{ + if (!m_config || !m_showRotationButton) { + return; + } + + const auto outputs = m_config->outputs(); + if (outputs.empty()) { + return; + } + + // HACK: Assume the output we care about is the first device + for (KScreen::OutputPtr output : outputs) { + // apparently it's possible to get nullptr outputs? + if (!output) { + continue; + } + + output->setRotation(m_rotateTo); + } + + auto setop = new KScreen::SetConfigOperation(m_config, this); + setop->exec(); + + updateShowRotationButton(); +} + +bool TaskPanel::showRotationButton() const +{ + return m_showRotationButton; +} + +void TaskPanel::updateShowRotationButton() +{ + if (!m_config) { + return; + } + + QOrientationReading *reading = m_sensor->reading(); + if (!reading) { + return; + } + + m_rotateTo = mapReadingOrientation(reading->orientation()); + + const auto outputs = m_config->outputs(); + + if (outputs.empty()) { + m_showRotationButton = false; + Q_EMIT showRotationButtonChanged(); + return; + } + + // HACK: Assume the output we care about is the first device + for (KScreen::OutputPtr output : outputs) { + if (!output) { + // apparently it's possible to get nullptr outputs? + continue; + } + if (output->autoRotatePolicy() == KScreen::Output::AutoRotatePolicy::Always) { + // only check displays that have autorotate on + continue; + } + + m_showRotationButton = output->rotation() != m_rotateTo; + Q_EMIT showRotationButtonChanged(); + return; + } + + m_showRotationButton = false; + Q_EMIT showRotationButtonChanged(); +} + K_PLUGIN_CLASS(TaskPanel) #include "taskpanel.moc" diff --git a/containments/taskpanel/taskpanel.h b/containments/taskpanel/taskpanel.h index 4135531f..9a17509c 100644 --- a/containments/taskpanel/taskpanel.h +++ b/containments/taskpanel/taskpanel.h @@ -7,13 +7,33 @@ #pragma once #include +#include + +#include class TaskPanel : public Plasma::Containment { Q_OBJECT + Q_PROPERTY(bool showRotationButton READ showRotationButton NOTIFY showRotationButtonChanged) public: TaskPanel(QObject *parent, const KPluginMetaData &data, const QVariantList &args); Q_INVOKABLE void triggerTaskSwitcher() const; + + bool showRotationButton() const; + Q_INVOKABLE void rotateToSuggestedRotation(); + +Q_SIGNALS: + void showRotationButtonChanged(); + +private Q_SLOTS: + void updateShowRotationButton(); + +private: + bool m_showRotationButton{false}; + KScreen::Output::Rotation m_rotateTo; + + KScreen::ConfigPtr m_config{nullptr}; + QOrientationSensor *m_sensor{nullptr}; };