15.1.965. tablet_qt/widgets/cameraqcamera.h

/*
    Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
    Created by Rudolf Cardinal (rnc1001@cam.ac.uk).

    This file is part of CamCOPS.

    CamCOPS is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    CamCOPS is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.
*/

#pragma once

#define CAMERA_LOAD_FROM_DISK_PROMPTLY

/*

SUMMARY OF DECISIONS about camera methods, updated 2023-01-04 for Qt6.5 :

Qt is now built with FFmpeg for all platforms except iOS.

1.  QCamera
    - Works mostly well on all platforms (with Android patch applied by the
    build script). On MacOS the preview is snowy but the actual photos taken
    are fine. https://bugreports.qt.io/browse/QTBUG-119834

2.  QML
    - multiple issues with our modified version of the declarative camera
    example:
    https://bugreports.qt.io/browse/QTBUG-111460 (closed but still observed)
    https://bugreports.qt.io/browse/QTBUG-116195
    https://bugreports.qt.io/browse/QTBUG-116292

    There is also a crash on MacOS when the Please wait... window
    (slowguiguard) is closed: "Window modal dialog has no transient parent"

*/

#include <QCamera>
#include <QImage>
#include <QImageCapture>
#include <QMediaCaptureSession>
#include <QPointer>
#include <QSet>
#include "widgets/openablewidget.h"
class QAbstractButton;
class QCameraDevice;
class QLabel;
class QQuickWidget;
class QPushButton;
class QStatusBar;
class QVideoFrame;
class QVideoWidget;


class CameraQCamera : public OpenableWidget
{
    // Widget to take a photo.
    // DEPRECATED at present in favour of QML version; see CameraQml.

    Q_OBJECT
public:
    // ========================================================================
    // Constructor/destructor
    // ========================================================================

    // Construct with stylesheet.
    CameraQCamera(const QString& stylesheet, QWidget* parent = nullptr);

    // Construct with QCameraDevice and stylesheet.
    CameraQCamera(const QCameraDevice& camera_device, const QString& stylesheet,
           QWidget* parent = nullptr);

    // Destructor.
    ~CameraQCamera();

    // ========================================================================
    // Public interface
    // ========================================================================

    // Emit the finished() signal.
    void finish();

    // Return the latest image captured.
    QImage image() const;

signals:
    // "We've captured this image."
    // - Note that QImage is copy-on-write; passing QImage is efficient.
    void imageCaptured(QImage image);

    // "User chose to cancel."
    void cancelled();

    // ========================================================================
    // Internals
    // ========================================================================
protected:

    // Update the display state for the buttons ("take", "lock", "cancel").
    void updateButtons();

    // Start the camera object.
    void startCamera();

    // Stop the camera object.
    void stopCamera();

    // Choose a camera.
    void setCamera(const QCameraDevice& camera_device);

    // Standard Qt overrides.
    void closeEvent(QCloseEvent* event);
    void keyPressEvent(QKeyEvent* event);
    void keyReleaseEvent(QKeyEvent* event);

protected slots:

    // "User has clicked the 'Take' button."
    void takeImage();

    // "Pop up a message showing a camera error."
    void displayCameraError(QCamera::Error value);

    // "Change the ready-for-capture state."
    void readyForCapture(bool ready);

    // "An image has arrived via a temporary disk file."
    void imageSaved(int id, const QString& filename);

    // "Display an error that occurred during the image capture process."
    void displayCaptureError(int id, QImageCapture::Error error,
                             const QString& error_string);

protected:
    QSharedPointer<QCamera> m_camera;  // our camera
    QSharedPointer<QImageCapture> m_capture;  // records images
    QPointer<QVideoWidget> m_viewfinder;  // our viewfinder
    QMediaCaptureSession m_capture_session;
    QPointer<QPushButton> m_button_cancel;  // "Cancel"
    QPointer<QStatusBar> m_status_bar;  // shows status messages
    QPointer<QAbstractButton> m_button_take;  // "Take"

    // QImageEncoderSettings m_image_settings;  // image encoder settings

    bool m_ready;  // ready to capture?
    bool m_capturing_image;  // currently capturing?
    bool m_exiting;  // closing/exiting?
    QImage m_most_recent_image;  // most recently captured image
#ifndef CAMERA_LOAD_FROM_DISK_PROMPTLY
    QSet<QString> m_filenames_for_deletion;  // temporary files to delete
    QString m_most_recent_filename;  // file with most recent image
    enum class CapturedState {  // ways we may have captured an image
        Nothing,
        File,
        Buffer,
    };
    CapturedState m_captured_state;  // what have we captured?
#endif
};