[{"id":24738,"web_url":"https://patchwork.libcamera.org/comment/24738/","msgid":"<YwQvqA+7QOxFdxgB@pendragon.ideasonboard.com>","date":"2022-08-23T01:38:48","subject":"Re: [libcamera-devel] [PATCH v8 1/8] qcam: Use QDialog for\n\tselection of cameras at startup","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Utkrash,\n\nThank you for the patch.\n\nOn Wed, Aug 10, 2022 at 08:33:42PM +0530, Utkarsh Tiwari via libcamera-devel wrote:\n> Currently we use QInputDialog convenience dialogs to allow the user to\n> select a camera. This doesn't allow adding of more information (such as\n> camera location, model etc).\n> \n> Create a QDialog with a QFormLayout that shows a QComboBox with camera\n> Ids. Use a QDialogButtonBox to provide buttons for accepting and\n> cancelling the action.\n> \n> The CameraSelectorDialog is only initialized the first time when the\n> MainWindow is created.\n> \n> From this commit we cease to auto select the camera if only a single\n> camera is available to libcamera. We would always display the selection\n> dialog with the exception being that being if the camera is supplied by\n> the console.\n\ns/by the console/on the command line/\n\n> Signed-off-by: Utkarsh Tiwari <utkarsh02t@gmail.com>\n> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> ---\n> Difference from v7:\n> \t1. Updated the commit message to inform of the behavioural change in\n> \t\tselecting the first camera.\n>  src/qcam/cam_select_dialog.cpp | 51 ++++++++++++++++++++++++++++++++++\n>  src/qcam/cam_select_dialog.h   | 34 +++++++++++++++++++++++\n>  src/qcam/main_window.cpp       | 44 +++++++++++------------------\n>  src/qcam/main_window.h         |  3 ++\n>  src/qcam/meson.build           |  2 ++\n>  5 files changed, 106 insertions(+), 28 deletions(-)\n>  create mode 100644 src/qcam/cam_select_dialog.cpp\n>  create mode 100644 src/qcam/cam_select_dialog.h\n> \n> diff --git a/src/qcam/cam_select_dialog.cpp b/src/qcam/cam_select_dialog.cpp\n> new file mode 100644\n> index 00000000..dceaa590\n> --- /dev/null\n> +++ b/src/qcam/cam_select_dialog.cpp\n> @@ -0,0 +1,51 @@\n> +/* SPDX-License-Identifier: GPL-2.0-or-later */\n> +/*\n> + * Copyright (C) 2022, Utkarsh Tiwari <utkarsh02t@gmail.com>\n> + *\n> + * cam_select_dialog.cpp - qcam - Camera Selection dialog\n> + */\n> +\n> +#include \"cam_select_dialog.h\"\n> +\n> +#include <string>\n\nYou don't need to include this header.\n\n> +\n> +#include <libcamera/camera.h>\n> +#include <libcamera/camera_manager.h>\n> +\n> +#include <QComboBox>\n> +#include <QDialog>\n\nYou can drop QDialog, as CameraSelectorDialog inherits from it, it's\nguaranteed to be included in cam_select_dialog.h.\n\n> +#include <QDialogButtonBox>\n> +#include <QFormLayout>\n> +#include <QString>\n> +\n> +CameraSelectorDialog::CameraSelectorDialog(libcamera::CameraManager *cameraManager,\n> +\t\t\t\t\t   QWidget *parent)\n> +\t: QDialog(parent), cm_(cameraManager)\n> +{\n> +\t/* Use a QFormLayout for the dialog. */\n> +\tQFormLayout *layout = new QFormLayout(this);\n> +\n> +\t/* Setup the camera id combo-box. */\n> +\tcameraIdComboBox_ = new QComboBox;\n> +\tfor (const auto &cam : cm_->cameras())\n> +\t\tcameraIdComboBox_->addItem(QString::fromStdString(cam->id()));\n> +\n> +\t/* Setup the QDialogButton Box */\n> +\tQDialogButtonBox *buttonBox =\n> +\t\tnew QDialogButtonBox(QDialogButtonBox::Ok |\n> +\t\t\t\t     QDialogButtonBox::Cancel);\n> +\n> +\tconnect(buttonBox, &QDialogButtonBox::accepted,\n> +\t\tthis, &QDialog::accept);\n> +\tconnect(buttonBox, &QDialogButtonBox::rejected,\n> +\t\tthis, &QDialog::reject);\n> +\n> +\t/* Set the layout. */\n> +\tlayout->addRow(\"Camera:\", cameraIdComboBox_);\n> +\tlayout->addWidget(buttonBox);\n> +}\n> +\n> +std::string CameraSelectorDialog::getCameraId()\n> +{\n> +\treturn cameraIdComboBox_->currentText().toStdString();\n> +}\n> diff --git a/src/qcam/cam_select_dialog.h b/src/qcam/cam_select_dialog.h\n> new file mode 100644\n> index 00000000..5544f49a\n> --- /dev/null\n> +++ b/src/qcam/cam_select_dialog.h\n> @@ -0,0 +1,34 @@\n> +/* SPDX-License-Identifier: GPL-2.0-or-later */\n> +/*\n> + * Copyright (C) 2022, Utkarsh Tiwari <utkarsh02t@gmail.com>\n> + *\n> + * cam_select_dialog.h - qcam - Camera Selection dialog\n> + */\n> +\n> +#pragma once\n> +\n> +#include <string>\n> +\n> +#include <libcamera/camera.h>\n> +#include <libcamera/camera_manager.h>\n> +\n> +#include <QComboBox>\n\nQComboxBox can be forward-declared (see main_window.h).\n\n> +#include <QDialog>\n> +\n> +class CameraSelectorDialog : public QDialog\n> +{\n> +\tQ_OBJECT\n> +public:\n> +\tCameraSelectorDialog(libcamera::CameraManager *cameraManager,\n> +\t\t\t     QWidget *parent);\n> +\n> +\t~CameraSelectorDialog() = default;\n\nDefining a function in the class definition, regardless of whether you\ndefine it with a manual implementation or with = default, results in the\nfunction being inlined. This can increase the binary size, and should\nthus only be done when needed. Here, you should write\n\n\tCameraSelectorDialog(libcamera::CameraManager *cameraManager,\n\t\t\t     QWidget *parent);\n\t~CameraSelectorDialog();\n\nand in the .cpp file add\n\nCameraSelectorDialog::~CameraSelectorDialog() = default;\n\n> +\n> +\tstd::string getCameraId();\n> +\n> +private:\n> +\tlibcamera::CameraManager *cm_;\n> +\n> +\t/* UI elements. */\n> +\tQComboBox *cameraIdComboBox_;\n> +};\n> diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp\n> index 7433d647..e794221a 100644\n> --- a/src/qcam/main_window.cpp\n> +++ b/src/qcam/main_window.cpp\n> @@ -19,7 +19,6 @@\n>  #include <QFileDialog>\n>  #include <QImage>\n>  #include <QImageWriter>\n> -#include <QInputDialog>\n>  #include <QMutexLocker>\n>  #include <QStandardPaths>\n>  #include <QStringList>\n> @@ -30,6 +29,7 @@\n>  \n>  #include \"../cam/image.h\"\n>  \n> +#include \"cam_select_dialog.h\"\n>  #include \"dng_writer.h\"\n>  #ifndef QT_NO_OPENGL\n>  #include \"viewfinder_gl.h\"\n> @@ -97,8 +97,8 @@ private:\n>  };\n>  \n>  MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options)\n> -\t: saveRaw_(nullptr), options_(options), cm_(cm), allocator_(nullptr),\n> -\t  isCapturing_(false), captureRaw_(false)\n> +\t: saveRaw_(nullptr), cameraSelectorDialog_(nullptr), options_(options),\n> +\t  cm_(cm), allocator_(nullptr), isCapturing_(false), captureRaw_(false)\n>  {\n>  \tint ret;\n>  \n> @@ -290,38 +290,26 @@ void MainWindow::switchCamera(int index)\n>  \n>  std::string MainWindow::chooseCamera()\n>  {\n> -\tQStringList cameras;\n> -\tbool result;\n> -\n> -\t/* If only one camera is available, use it automatically. */\n> -\tif (cm_->cameras().size() == 1)\n> -\t\treturn cm_->cameras()[0]->id();\n> -\n> -\t/* Present a dialog box to pick a camera. */\n> -\tfor (const std::shared_ptr<Camera> &cam : cm_->cameras())\n> -\t\tcameras.append(QString::fromStdString(cam->id()));\n> -\n> -\tQString id = QInputDialog::getItem(this, \"Select Camera\",\n> -\t\t\t\t\t   \"Camera:\", cameras, 0,\n> -\t\t\t\t\t   false, &result);\n> -\tif (!result)\n> -\t\treturn std::string();\n> -\n> -\treturn id.toStdString();\n> -}\n> -\n> -int MainWindow::openCamera()\n> -{\n> -\tstd::string cameraName;\n> +\t/* Construct the selection dialog, only the first time. */\n> +\tif (!cameraSelectorDialog_)\n> +\t\tcameraSelectorDialog_ = new CameraSelectorDialog(cm_, this);\n>  \n>  \t/*\n>  \t * Use the camera specified on the command line, if any, or display the\n>  \t * camera selection dialog box otherwise.\n>  \t */\n>  \tif (options_.isSet(OptCamera))\n> -\t\tcameraName = static_cast<std::string>(options_[OptCamera]);\n> +\t\treturn static_cast<std::string>(options_[OptCamera]);\n> +\n> +\tif (cameraSelectorDialog_->exec() == QDialog::Accepted)\n> +\t\treturn cameraSelectorDialog_->getCameraId();\n>  \telse\n> -\t\tcameraName = chooseCamera();\n> +\t\treturn std::string();\n> +}\n> +\n> +int MainWindow::openCamera()\n> +{\n> +\tstd::string cameraName = chooseCamera();\n>  \n>  \tif (cameraName == \"\")\n>  \t\treturn -EINVAL;\n> diff --git a/src/qcam/main_window.h b/src/qcam/main_window.h\n> index fc70920f..4ad5e6e9 100644\n> --- a/src/qcam/main_window.h\n> +++ b/src/qcam/main_window.h\n> @@ -28,6 +28,7 @@\n>  \n>  #include \"../cam/stream_options.h\"\n>  \n> +#include \"cam_select_dialog.h\"\n>  #include \"viewfinder.h\"\n>  \n>  class QAction;\n> @@ -99,6 +100,8 @@ private:\n>  \tQString title_;\n>  \tQTimer titleTimer_;\n>  \n> +\tCameraSelectorDialog *cameraSelectorDialog_;\n\nYou can forward-declare CameraSelectorDialog the same way we do for\nImage and HotplugEvent.\n\nWith those small issues addressed,\n\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\n> +\n>  \t/* Options */\n>  \tconst OptionsParser::Options &options_;\n>  \n> diff --git a/src/qcam/meson.build b/src/qcam/meson.build\n> index c46f4631..61861ea6 100644\n> --- a/src/qcam/meson.build\n> +++ b/src/qcam/meson.build\n> @@ -18,6 +18,7 @@ qcam_sources = files([\n>      '../cam/image.cpp',\n>      '../cam/options.cpp',\n>      '../cam/stream_options.cpp',\n> +    'cam_select_dialog.cpp',\n>      'format_converter.cpp',\n>      'main.cpp',\n>      'main_window.cpp',\n> @@ -26,6 +27,7 @@ qcam_sources = files([\n>  ])\n>  \n>  qcam_moc_headers = files([\n> +    'cam_select_dialog.h',\n>      'main_window.h',\n>      'viewfinder_qt.h',\n>  ])","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 1913CC0DA4\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 23 Aug 2022 01:38:56 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 47AEE61FC0;\n\tTue, 23 Aug 2022 03:38:55 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 8727860E25\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 23 Aug 2022 03:38:53 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id EFDA22B3;\n\tTue, 23 Aug 2022 03:38:52 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1661218735;\n\tbh=RPwRnOhPRXlACXqC/5PK/tIDXIz1jGqRpGrB8oOpsnE=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=gPYI7gWOXZfqpnuH3sP0Wg/zG0BLb4WXxjTCfG6zqFkjPYRZnQeE5pKu4Qr87rxk6\n\t7h4HmAxvWTGqWbKRxq0Mge0Wq1qBEhIeafBO4dIrg3KbBH5qfFFUUrTg3XKlUzBRRi\n\taQzc7xfeCflT8mpEiPsoIdoAQVvr0S5dDGpG0CrRbjPgBPD1JDemtSwxfSi5RRt2qU\n\tJQehmljI1PsFfFYSFZ6/46VFR9SyPrvcLwT0cRBqKwe7V0OAmhoCOi942xUiusVqk9\n\th6dO4Dv3NVNbqo8mOlSggXaGk+T0rkbdRxwkA4/z2Qt+RpohLZy77GkZB0A9eugg5g\n\txPh47Pjz9E0pw==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1661218733;\n\tbh=RPwRnOhPRXlACXqC/5PK/tIDXIz1jGqRpGrB8oOpsnE=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=lJ82RDhFGw+0lRHpCwmvL6ePYhHUGL9wV0TONsorCMnTUQgHf0LL3HkVoXYvcqoTZ\n\t2pe4vKNhnIL7xcLIDvcXFJSgiMS6FW/s7dUt9bZCBlQ91TPYb/D4cK5HPexzhNCfNR\n\tQPeYHbsIsyNsFh2bi2k+R5uzX4FkgxjRlR5EHhOc="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"lJ82RDhF\"; dkim-atps=neutral","Date":"Tue, 23 Aug 2022 04:38:48 +0300","To":"Utkarsh Tiwari <utkarsh02t@gmail.com>","Message-ID":"<YwQvqA+7QOxFdxgB@pendragon.ideasonboard.com>","References":"<20220810150349.414043-1-utkarsh02t@gmail.com>\n\t<20220810150349.414043-2-utkarsh02t@gmail.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20220810150349.414043-2-utkarsh02t@gmail.com>","Subject":"Re: [libcamera-devel] [PATCH v8 1/8] qcam: Use QDialog for\n\tselection of cameras at startup","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","From":"Laurent Pinchart via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]