navigationpanel: Add manual screen rotation button

When the device is rotated and autorotate is off, a button will appear
on the navigation panel to manually rotate.

This is specific to the navigation panel, perhaps we can have a floating
button in gesture-only mode similar to Android?

TODO: PoC, I haven't yet actually tested this on device. I also need to
make sure that I check for whether autorotation is enabled on the
output.
This commit is contained in:
Devin Lin 2024-11-07 23:52:45 -08:00
parent aa3e42f65a
commit 3d9ddbde15
5 changed files with 188 additions and 0 deletions

View file

@ -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
}
}
]
}

View file

@ -10,7 +10,9 @@ target_link_libraries(org.kde.plasma.mobile.taskpanel
Qt::DBus
Qt::Qml
Qt::Quick
Qt::Sensors
Plasma::Plasma
KF6::Screen
)

View file

@ -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 ||

View file

@ -11,12 +11,54 @@
#include <QDebug>
#include <QGuiApplication>
#include <kscreen/configmonitor.h>
#include <kscreen/getconfigoperation.h>
#include <kscreen/output.h>
#include <kscreen/setconfigoperation.h>
// 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<KScreen::GetConfigOperation *>(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"

View file

@ -7,13 +7,33 @@
#pragma once
#include <Plasma/Containment>
#include <QOrientationSensor>
#include <kscreen/config.h>
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};
};