Skip to content

Commit ce391ab

Browse files
authored
[FL-3196] Lefty mode (#172)
* Update protobuf definitions, add gui screen orientation * Rotate the screen streaming widgets if flipper is in lefty mode * Improve input event handling * Improve lefty mode
1 parent f039582 commit ce391ab

18 files changed

+222
-214
lines changed

application/application.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "screencanvas.h"
1919
#include "preferences.h"
2020
#include "backenderror.h"
21+
#include "inputevent.h"
2122
#include "logger.h"
2223

2324
Q_LOGGING_CATEGORY(LOG_APP, "APP")
@@ -189,6 +190,7 @@ void Application::initQmlTypes()
189190
qmlRegisterType<ScreenCanvas>("QFlipper", 1, 0, "ScreenCanvas");
190191

191192
qmlRegisterUncreatableType<BackendError>("QFlipper", 1, 0, "BackendError", QStringLiteral("This class is only a enum container"));
193+
qmlRegisterUncreatableType<InputEvent>("QFlipper", 1, 0, "InputEvent", QStringLiteral("This class is only a enum container"));
192194
qmlRegisterUncreatableType<ApplicationBackend>("QFlipper", 1, 0, "ApplicationBackend", QStringLiteral("This class is meant to be created from c++"));
193195
qmlRegisterUncreatableType<ApplicationUpdater>("QFlipper", 1, 0, "ApplicationUpdater", QStringLiteral("This class is meant to be created from c++"));
194196

application/components/DeviceWidget.qml

+1-4
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,7 @@ Image {
7373
foregroundColor: Theme.color.darkorange1
7474
backgroundColor: Theme.color.lightorange2
7575

76-
canvasWidth: Backend.screenStreamer.screenSize.width
77-
canvasHeight: Backend.screenStreamer.screenSize.height
78-
79-
data: Backend.screenStreamer.screenData
76+
frame: Backend.screenStreamer.screenFrame
8077
}
8178

8279
ExpandWidget {

application/components/DirectionalKeypad.qml

+31-47
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import QtQuick.Controls 2.15
33
import QtQuick.Layouts 1.15
44

55
import Theme 1.0
6+
import QFlipper 1.0
67

78
Item {
89
id: control
@@ -42,11 +43,11 @@ Item {
4243
rotation: 180
4344
padding: control.spacing
4445

45-
onPressed: inputEvent(DirectionalKeypad.InputKey.Up, DirectionalKeypad.InputType.Press)
46-
onReleased: inputEvent(DirectionalKeypad.InputKey.Up, DirectionalKeypad.InputType.Release)
47-
onShortPress: inputEvent(DirectionalKeypad.InputKey.Up, DirectionalKeypad.InputType.Short)
48-
onLongPress: inputEvent(DirectionalKeypad.InputKey.Up, DirectionalKeypad.InputType.Long)
49-
onRepeat: inputEvent(DirectionalKeypad.InputKey.Up, DirectionalKeypad.InputType.Repeat)
46+
onPressed: inputEvent(InputEvent.Up, InputEvent.Press)
47+
onReleased: inputEvent(InputEvent.Up, InputEvent.Release)
48+
onShortPress: inputEvent(InputEvent.Up, InputEvent.Short)
49+
onLongPress: inputEvent(InputEvent.Up, InputEvent.Long)
50+
onRepeat: inputEvent(InputEvent.Up, InputEvent.Repeat)
5051
}
5152

5253
KeypadButton {
@@ -60,11 +61,11 @@ Item {
6061
rotation: 90
6162
padding: control.spacing
6263

63-
onPressed: inputEvent(DirectionalKeypad.InputKey.Left, DirectionalKeypad.InputType.Press)
64-
onReleased: inputEvent(DirectionalKeypad.InputKey.Left, DirectionalKeypad.InputType.Release)
65-
onShortPress: inputEvent(DirectionalKeypad.InputKey.Left, DirectionalKeypad.InputType.Short)
66-
onLongPress: inputEvent(DirectionalKeypad.InputKey.Left, DirectionalKeypad.InputType.Long)
67-
onRepeat: inputEvent(DirectionalKeypad.InputKey.Left, DirectionalKeypad.InputType.Repeat)
64+
onPressed: inputEvent(InputEvent.Left, InputEvent.Press)
65+
onReleased: inputEvent(InputEvent.Left, InputEvent.Release)
66+
onShortPress: inputEvent(InputEvent.Left, InputEvent.Short)
67+
onLongPress: inputEvent(InputEvent.Left, InputEvent.Long)
68+
onRepeat: inputEvent(InputEvent.Left, InputEvent.Repeat)
6869
}
6970

7071
KeypadButton {
@@ -75,11 +76,11 @@ Item {
7576
icon.width: 52
7677
icon.height: 52
7778

78-
onPressed: inputEvent(DirectionalKeypad.InputKey.Ok, DirectionalKeypad.InputType.Press)
79-
onReleased: inputEvent(DirectionalKeypad.InputKey.Ok, DirectionalKeypad.InputType.Release)
80-
onShortPress: inputEvent(DirectionalKeypad.InputKey.Ok, DirectionalKeypad.InputType.Short)
81-
onLongPress: inputEvent(DirectionalKeypad.InputKey.Ok, DirectionalKeypad.InputType.Long)
82-
onRepeat: inputEvent(DirectionalKeypad.InputKey.Ok, DirectionalKeypad.InputType.Repeat)
79+
onPressed: inputEvent(InputEvent.Ok, InputEvent.Press)
80+
onReleased: inputEvent(InputEvent.Ok, InputEvent.Release)
81+
onShortPress: inputEvent(InputEvent.Ok, InputEvent.Short)
82+
onLongPress: inputEvent(InputEvent.Ok, InputEvent.Long)
83+
onRepeat: inputEvent(InputEvent.Ok, InputEvent.Repeat)
8384
}
8485

8586
KeypadButton {
@@ -93,11 +94,11 @@ Item {
9394
rotation: -90
9495
padding: control.spacing
9596

96-
onPressed: inputEvent(DirectionalKeypad.InputKey.Right, DirectionalKeypad.InputType.Press)
97-
onReleased: inputEvent(DirectionalKeypad.InputKey.Right, DirectionalKeypad.InputType.Release)
98-
onShortPress: inputEvent(DirectionalKeypad.InputKey.Right, DirectionalKeypad.InputType.Short)
99-
onLongPress: inputEvent(DirectionalKeypad.InputKey.Right, DirectionalKeypad.InputType.Long)
100-
onRepeat: inputEvent(DirectionalKeypad.InputKey.Right, DirectionalKeypad.InputType.Repeat)
97+
onPressed: inputEvent(InputEvent.Right, InputEvent.Press)
98+
onReleased: inputEvent(InputEvent.Right, InputEvent.Release)
99+
onShortPress: inputEvent(InputEvent.Right, InputEvent.Short)
100+
onLongPress: inputEvent(InputEvent.Right, InputEvent.Long)
101+
onRepeat: inputEvent(InputEvent.Right, InputEvent.Repeat)
101102
}
102103

103104
KeypadButton {
@@ -112,11 +113,11 @@ Item {
112113
icon.height: 28
113114
padding: control.spacing
114115

115-
onPressed: inputEvent(DirectionalKeypad.InputKey.Down, DirectionalKeypad.InputType.Press)
116-
onReleased: inputEvent(DirectionalKeypad.InputKey.Down, DirectionalKeypad.InputType.Release)
117-
onShortPress: inputEvent(DirectionalKeypad.InputKey.Down, DirectionalKeypad.InputType.Short)
118-
onLongPress: inputEvent(DirectionalKeypad.InputKey.Down, DirectionalKeypad.InputType.Long)
119-
onRepeat: inputEvent(DirectionalKeypad.InputKey.Down, DirectionalKeypad.InputType.Repeat)
116+
onPressed: inputEvent(InputEvent.Down, InputEvent.Press)
117+
onReleased: inputEvent(InputEvent.Down, InputEvent.Release)
118+
onShortPress: inputEvent(InputEvent.Down, InputEvent.Short)
119+
onLongPress: inputEvent(InputEvent.Down, InputEvent.Long)
120+
onRepeat: inputEvent(InputEvent.Down, InputEvent.Repeat)
120121
}
121122
}
122123
}
@@ -132,11 +133,11 @@ Item {
132133
icon.width: 52
133134
icon.height: 52
134135

135-
onPressed: inputEvent(DirectionalKeypad.InputKey.Back, DirectionalKeypad.InputType.Press)
136-
onReleased: inputEvent(DirectionalKeypad.InputKey.Back, DirectionalKeypad.InputType.Release)
137-
onShortPress: inputEvent(DirectionalKeypad.InputKey.Back, DirectionalKeypad.InputType.Short)
138-
onLongPress: inputEvent(DirectionalKeypad.InputKey.Back, DirectionalKeypad.InputType.Long)
139-
onRepeat: inputEvent(DirectionalKeypad.InputKey.Back, DirectionalKeypad.InputType.Repeat)
136+
onPressed: inputEvent(InputEvent.Back, InputEvent.Press)
137+
onReleased: inputEvent(InputEvent.Back, InputEvent.Release)
138+
onShortPress: inputEvent(InputEvent.Back, InputEvent.Short)
139+
onLongPress: inputEvent(InputEvent.Back, InputEvent.Long)
140+
onRepeat: inputEvent(InputEvent.Back, InputEvent.Repeat)
140141
}
141142

142143
Keys.onPressed: function(event) {
@@ -165,23 +166,6 @@ Item {
165166
event.accepted = true;
166167
}
167168

168-
enum InputKey {
169-
Up,
170-
Down,
171-
Right,
172-
Left,
173-
Ok,
174-
Back
175-
}
176-
177-
enum InputType {
178-
Press,
179-
Release,
180-
Short,
181-
Long,
182-
Repeat
183-
}
184-
185169
function findButton(key) {
186170
switch(key) {
187171
case Qt.Key_Left:

application/components/StreamOverlay.qml

+2-8
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,8 @@ AbstractOverlay {
3030

3131
foregroundColor: "black"
3232
backgroundColor: Theme.color.lightorange2
33-
34-
canvasWidth: Backend.screenStreamer.screenSize.width
35-
canvasHeight: Backend.screenStreamer.screenSize.height
36-
37-
width: canvasWidth * 4
38-
height: canvasHeight * 4
39-
40-
data: Backend.screenStreamer.screenData
33+
zoomFactor: 4
34+
frame: Backend.screenStreamer.screenFrame
4135
}
4236

4337
RowLayout {

application/screencanvas.cpp

+45-73
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,45 @@
11
#include "screencanvas.h"
22

33
#include <cmath>
4+
45
#include <QPainter>
56
#include <QClipboard>
67
#include <QGuiApplication>
78

8-
#include "debug.h"
9-
109
ScreenCanvas::ScreenCanvas(QQuickItem *parent):
1110
QQuickPaintedItem(parent),
1211
m_foreground(QColor(0x00, 0x00, 0x00)),
1312
m_background(QColor(0xFF, 0xFF, 0xFF)),
14-
m_canvas(QImage(1, 1, QImage::Format_RGB32))
15-
{}
13+
m_canvas(QImage(1, 1, QImage::Format_RGB32)),
14+
m_zoomFactor(1.0)
15+
{
16+
connect(this, &ScreenCanvas::zoomFactorChanged, this, &ScreenCanvas::updateImplicitSize);
17+
connect(this, &ScreenCanvas::canvasSizeChanged, this, &ScreenCanvas::updateImplicitSize);
18+
}
1619

17-
const QByteArray &ScreenCanvas::data() const
20+
const ScreenFrame &ScreenCanvas::frame() const
1821
{
19-
static QByteArray dummy;
22+
static const ScreenFrame dummy {};
2023
return dummy;
2124
}
2225

23-
void ScreenCanvas::setData(const QByteArray &data)
26+
void ScreenCanvas::setFrame(const ScreenFrame &frame)
2427
{
25-
if(data.isEmpty()) {
28+
if(frame.pixelData.isEmpty() || frame.size.isEmpty()) {
2629
return;
2730
}
2831

29-
for (auto x = 0; x < canvasWidth(); x++) {
30-
for (auto y = 0; y < canvasHeight(); y++) {
31-
const auto i = y / 8 * canvasWidth() + x;
32+
setCanvasSize(frame.size);
33+
34+
for (auto x = 0; x < m_canvas.width(); x++) {
35+
for (auto y = 0; y < m_canvas.height(); y++) {
36+
const auto i = y / 8 * m_canvas.width() + x;
3237
const auto z = y % 8;
33-
const auto color = ((data.at(i) & (1 << z))) ? m_foreground : m_background;
34-
m_canvas.setPixelColor(x, y, color);
38+
const auto color = ((frame.pixelData.at(i) & (1 << z))) ? m_foreground : m_background;
39+
40+
m_canvas.setPixelColor(frame.isFlipped ? m_canvas.width() - x - 1 : x,
41+
frame.isFlipped ? m_canvas.height() - y - 1 : y,
42+
color);
3543
}
3644
}
3745

@@ -43,7 +51,7 @@ void ScreenCanvas::paint(QPainter *painter)
4351
const auto bw = boundingRect().width();
4452
const auto bh = boundingRect().height();
4553

46-
const auto aspectRatio = (double)canvasWidth() / canvasHeight();
54+
const auto aspectRatio = (double)m_canvas.width() / m_canvas.height();
4755

4856
auto w = bw;
4957
auto h = floor(w / aspectRatio);
@@ -53,11 +61,8 @@ void ScreenCanvas::paint(QPainter *painter)
5361
w = bh * aspectRatio;
5462
}
5563

56-
w -= ((int)w % (int)canvasWidth());
57-
h -= ((int)h % (int)canvasHeight());
58-
59-
setRenderWidth(w);
60-
setRenderHeight(h);
64+
w -= ((int)w % m_canvas.width());
65+
h -= ((int)h % m_canvas.height());
6166

6267
const auto dw = (bw - w) / 2;
6368
const auto dh = (bh - h) / 2;
@@ -66,50 +71,20 @@ void ScreenCanvas::paint(QPainter *painter)
6671
painter->drawImage(canvasRect, m_canvas);
6772
}
6873

69-
qreal ScreenCanvas::canvasWidth() const
70-
{
71-
return m_canvas.width();
72-
}
73-
74-
void ScreenCanvas::setCanvasWidth(qreal w)
75-
{
76-
if (qFuzzyCompare(canvasWidth(), w)) {
77-
return;
78-
}
79-
80-
m_canvas = QImage(w, canvasHeight(), QImage::Format_RGB32);
81-
m_canvas.fill(m_background);
82-
emit canvasWidthChanged();
83-
84-
update();
85-
}
86-
87-
qreal ScreenCanvas::canvasHeight() const
74+
qreal ScreenCanvas::zoomFactor() const
8875
{
89-
return m_canvas.height();
76+
return m_zoomFactor;
9077
}
9178

92-
void ScreenCanvas::setCanvasHeight(qreal h)
79+
void ScreenCanvas::setZoomFactor(qreal zoom)
9380
{
94-
if(qFuzzyCompare(canvasHeight(), h)) {
81+
if(qFuzzyCompare(m_zoomFactor, zoom)) {
9582
return;
9683
}
9784

98-
m_canvas = QImage(canvasWidth(), h, QImage::Format_RGB32);
99-
m_canvas.fill(m_background);
100-
emit canvasHeightChanged();
101-
102-
update();
103-
}
104-
105-
qreal ScreenCanvas::renderWidth() const
106-
{
107-
return m_renderWidth;
108-
}
85+
m_zoomFactor = zoom;
86+
emit zoomFactorChanged();
10987

110-
qreal ScreenCanvas::renderHeight() const
111-
{
112-
return m_renderHeight;
11388
}
11489

11590
const QColor &ScreenCanvas::foregroundColor() const
@@ -142,41 +117,38 @@ void ScreenCanvas::setBackgroundColor(const QColor &color)
142117
emit backgroundColorChanged();
143118
}
144119

145-
void ScreenCanvas::saveImage(const QUrl &url, int scale)
120+
bool ScreenCanvas::saveImage(const QUrl &url, int scale)
146121
{
147-
check_return_void(canvas(scale).save(url.toLocalFile()), "Failed to save image");
122+
return canvas(scale).save(url.toLocalFile());
148123
}
149124

150125
void ScreenCanvas::copyToClipboard(int scale)
151126
{
152127
qGuiApp->clipboard()->setImage(canvas(scale));
153128
}
154129

155-
void ScreenCanvas::setRenderWidth(qreal w)
130+
void ScreenCanvas::updateImplicitSize()
156131
{
157-
if(qFuzzyCompare(m_renderWidth, w)) {
132+
setImplicitSize(m_zoomFactor * m_canvas.width(), m_zoomFactor * m_canvas.height());
133+
}
134+
135+
void ScreenCanvas::setCanvasSize(const QSize &size)
136+
{
137+
if(size == m_canvas.size()) {
158138
return;
159139
}
160140

161-
m_renderWidth = w;
162-
emit renderWidthChanged();
141+
m_canvas = QImage(size, QImage::Format_RGB32);
142+
m_canvas.fill(m_background);
143+
144+
emit canvasSizeChanged();
163145
}
164146

165147
const QImage ScreenCanvas::canvas(int scale) const
166148
{
167149
if(scale == 0) {
168-
return m_canvas.scaled(m_renderWidth, m_renderHeight);
150+
return m_canvas.scaled(m_canvas.width() * m_zoomFactor, m_canvas.height() * m_zoomFactor);
169151
} else {
170-
return m_canvas.scaled(canvasWidth() * scale, canvasHeight() * scale);
152+
return m_canvas.scaled(m_canvas.width() * scale, m_canvas.height() * scale);
171153
}
172154
}
173-
174-
void ScreenCanvas::setRenderHeight(qreal h)
175-
{
176-
if(qFuzzyCompare(m_renderHeight, h)) {
177-
return;
178-
}
179-
180-
m_renderHeight = h;
181-
emit renderHeightChanged();
182-
}

0 commit comments

Comments
 (0)