Implement screen orientation (#202)

This commit is contained in:
Georgii Surkov 2023-11-03 16:19:53 +03:00 committed by GitHub
parent e2c10f8a35
commit 52f4ce220e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 99 additions and 44 deletions

View File

@ -11,7 +11,8 @@ ScreenCanvas::ScreenCanvas(QQuickItem *parent):
m_foreground(QColor(0x00, 0x00, 0x00)),
m_background(QColor(0xFF, 0xFF, 0xFF)),
m_canvas(QImage(1, 1, QImage::Format_RGB32)),
m_zoomFactor(1.0)
m_zoomFactor(1.0),
m_orientation(Qt::LandscapeOrientation)
{
connect(this, &ScreenCanvas::zoomFactorChanged, this, &ScreenCanvas::updateImplicitSize);
connect(this, &ScreenCanvas::canvasSizeChanged, this, &ScreenCanvas::updateImplicitSize);
@ -30,6 +31,7 @@ void ScreenCanvas::setFrame(const ScreenFrame &frame)
}
setCanvasSize(frame.size);
setCanvasOrientation(frame.orientation);
for (auto x = 0; x < m_canvas.width(); x++) {
for (auto y = 0; y < m_canvas.height(); y++) {
@ -37,9 +39,7 @@ void ScreenCanvas::setFrame(const ScreenFrame &frame)
const auto z = y % 8;
const auto color = ((frame.pixelData.at(i) & (1 << z))) ? m_foreground : m_background;
m_canvas.setPixelColor(frame.isFlipped ? m_canvas.width() - x - 1 : x,
frame.isFlipped ? m_canvas.height() - y - 1 : y,
color);
m_canvas.setPixelColor(x, y, color);
}
}
@ -48,27 +48,8 @@ void ScreenCanvas::setFrame(const ScreenFrame &frame)
void ScreenCanvas::paint(QPainter *painter)
{
const auto bw = boundingRect().width();
const auto bh = boundingRect().height();
const auto aspectRatio = (double)m_canvas.width() / m_canvas.height();
auto w = bw;
auto h = floor(w / aspectRatio);
if(h > bh) {
h = bh;
w = bh * aspectRatio;
}
w -= ((int)w % m_canvas.width());
h -= ((int)h % m_canvas.height());
const auto dw = (bw - w) / 2;
const auto dh = (bh - h) / 2;
const QRectF canvasRect(dw, dh, w, h);
painter->drawImage(canvasRect, m_canvas);
painter->drawImage(canvasRect(), m_canvas.transformed(canvasTransform()));
}
qreal ScreenCanvas::zoomFactor() const
@ -144,11 +125,83 @@ void ScreenCanvas::setCanvasSize(const QSize &size)
emit canvasSizeChanged();
}
void ScreenCanvas::setCanvasOrientation(Qt::ScreenOrientation orientation)
{
m_orientation = orientation;
}
QTransform ScreenCanvas::canvasTransform() const
{
switch (m_orientation) {
case Qt::InvertedLandscapeOrientation:
return QTransform().rotate(180);
case Qt::PortraitOrientation:
return QTransform().rotate(isLandscapeOnly() ? 0 : 90);
case Qt::InvertedPortraitOrientation:
return QTransform().rotate(isLandscapeOnly() ? 180 : -90);
case Qt::LandscapeOrientation:
default:
return QTransform();
}
}
QRectF ScreenCanvas::canvasRect() const
{
const auto totalWidth = boundingRect().width();
const auto totalHeight = boundingRect().height();
const auto isRegular = isLandscapeOrientation() || isLandscapeOnly();
const auto canvasWidth = isRegular ? m_canvas.width() : m_canvas.height();
const auto canvasHeight = isRegular ? m_canvas.height() : m_canvas.width();
const auto aspectRatio = static_cast<qreal>(canvasWidth) / canvasHeight;
auto drawWidth = totalWidth;
auto drawHeight = floor(drawWidth / aspectRatio);
if(drawHeight > totalHeight) {
drawHeight = totalHeight;
drawWidth = totalHeight * aspectRatio;
}
if(drawWidth > canvasWidth) {
drawWidth -= (static_cast<int>(drawWidth) % canvasWidth);
}
if(drawHeight > canvasHeight) {
drawHeight -= (static_cast<int>(drawHeight) % canvasHeight);
}
const auto offsetX = (totalWidth - drawWidth) / 2;
const auto offsetY = (totalHeight - drawHeight) / 2;
return QRectF(offsetX, offsetY, drawWidth, drawHeight);
}
QSize ScreenCanvas::canvasSize() const
{
return QSize(isLandscapeOrientation() ? m_canvas.width() : m_canvas.height(),
isLandscapeOrientation() ? m_canvas.height() : m_canvas.width());
}
bool ScreenCanvas::isLandscapeOrientation() const
{
return m_orientation == Qt::LandscapeOrientation ||
m_orientation == Qt::InvertedLandscapeOrientation;
}
bool ScreenCanvas::isLandscapeOnly() const
{
return (boundingRect().width() < canvasSize().width()) ||
(boundingRect().height() < canvasSize().height());
}
const QImage ScreenCanvas::canvas(int scale) const
{
if(scale == 0) {
return m_canvas.scaled(m_canvas.width() * m_zoomFactor, m_canvas.height() * m_zoomFactor);
return m_canvas.scaled(m_canvas.width() * m_zoomFactor, m_canvas.height() * m_zoomFactor).transformed(canvasTransform());
} else {
return m_canvas.scaled(m_canvas.width() * scale, m_canvas.height() * scale);
return m_canvas.scaled(m_canvas.width() * scale, m_canvas.height() * scale).transformed(canvasTransform());
}
}

View File

@ -49,12 +49,21 @@ private slots:
private:
void setCanvasSize(const QSize &size);
void setCanvasOrientation(Qt::ScreenOrientation orientation);
const QImage canvas(int scale = 0) const;
QTransform canvasTransform() const;
QRectF canvasRect() const;
QSize canvasSize() const;
bool isLandscapeOrientation() const;
bool isLandscapeOnly() const;
const QImage canvas(int scale = 0) const;
QColor m_foreground;
QColor m_background;
QImage m_canvas;
qreal m_zoomFactor;
Qt::ScreenOrientation m_orientation;
};

View File

@ -61,7 +61,7 @@ void ScreenStreamer::setDevice(FlipperZero *device)
setScreenFrame({
transposeImage(QByteArray((char*)default_bits, sizeof(default_bits)), default_width, default_height),
QSize(SCREEN_FRAME_WIDTH, SCREEN_FRAME_HEIGHT),
false
Qt::LandscapeOrientation,
});
if(device) {
@ -179,7 +179,7 @@ void ScreenStreamer::onBroadcastResponseReceived(QObject *response)
setScreenFrame({
screenFrameResponse->screenFrame(),
QSize(SCREEN_FRAME_WIDTH, SCREEN_FRAME_HEIGHT),
screenFrameResponse->screenOrientation() == GuiScreenFrameResponseInterface::HorizontalFlip
screenFrameResponse->screenOrientation(),
});
}
}

View File

@ -7,7 +7,7 @@
struct ScreenFrame {
QByteArray pixelData;
QSize size;
bool isFlipped;
Qt::ScreenOrientation orientation;
};
Q_DECLARE_METATYPE(ScreenFrame)

View File

@ -10,17 +10,17 @@ const QByteArray GuiScreenFrameResponse::screenFrame() const
return QByteArray((const char*)f->bytes, f->size);
}
GuiScreenFrameResponseInterface::ScreenOrientation GuiScreenFrameResponse::screenOrientation() const
Qt::ScreenOrientation GuiScreenFrameResponse::screenOrientation() const
{
switch(message().content.gui_screen_frame.orientation) {
case PB_Gui_ScreenOrientation_HORIZONTAL_FLIP:
return ScreenOrientation::HorizontalFlip;
return Qt::InvertedLandscapeOrientation;
case PB_Gui_ScreenOrientation_VERTICAL:
return ScreenOrientation::Vertical;
return Qt::PortraitOrientation;
case PB_Gui_ScreenOrientation_VERTICAL_FLIP:
return ScreenOrientation::VerticalFlip;
return Qt::InvertedPortraitOrientation;
case PB_Gui_ScreenOrientation_HORIZONTAL:
default:
return ScreenOrientation::Horizontal;
return Qt::LandscapeOrientation;
}
}

View File

@ -11,5 +11,5 @@ class GuiScreenFrameResponse : public MainResponse, public GuiScreenFrameRespons
public:
GuiScreenFrameResponse(MessageWrapper &wrapper, QObject *parent = nullptr);
const QByteArray screenFrame() const override;
ScreenOrientation screenOrientation() const override;
Qt::ScreenOrientation screenOrientation() const override;
};

View File

@ -6,15 +6,8 @@
class GuiScreenFrameResponseInterface
{
public:
enum ScreenOrientation {
Horizontal,
HorizontalFlip,
Vertical,
VerticalFlip,
};
virtual const QByteArray screenFrame() const = 0;
virtual ScreenOrientation screenOrientation() const = 0;
virtual Qt::ScreenOrientation screenOrientation() const = 0;
};
QT_BEGIN_NAMESPACE