15.1.347. tablet_qt/menu/widgettestmenu.cpp

/*
    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/>.
*/

#include "widgettestmenu.h"

#include <QDebug>
#include <QPushButton>
#include <QRandomGenerator>
#include <QtGlobal>
#include <QVBoxLayout>

#include "common/cssconst.h"
#include "common/textconst.h"
#include "common/uiconst.h"
#include "dbobjects/blob.h"
#include "diagnosis/icd10.h"
#include "dialogs/debugdialog.h"
#include "graphics/graphicsfunc.h"
#include "layouts/flowlayouthfw.h"
#include "lib/debugfunc.h"
#include "lib/layoutdumper.h"
#include "lib/sizehelpers.h"
#include "lib/uifunc.h"
#include "menulib/menuitem.h"
#include "qcustomplot/qcustomplot.h"
#include "questionnairelib/mcqfunc.h"
#include "questionnairelib/quaudioplayer.h"
#include "questionnairelib/quboolean.h"
#include "questionnairelib/qubutton.h"
#include "questionnairelib/qucanvas.h"
#include "questionnairelib/qucountdown.h"
#include "questionnairelib/qudatetime.h"
#include "questionnairelib/qudiagnosticcode.h"
#include "questionnairelib/questionnaire.h"
#include "questionnairelib/questionnaireheader.h"
#include "questionnairelib/quheading.h"
#include "questionnairelib/quhorizontalline.h"
#include "questionnairelib/quimage.h"
#include "questionnairelib/qulineedit.h"
#include "questionnairelib/qulineeditdouble.h"
#include "questionnairelib/qulineeditint64.h"
#include "questionnairelib/qulineeditinteger.h"
#include "questionnairelib/qulineeditnhsnumber.h"
#include "questionnairelib/qulineedituint64.h"
#include "questionnairelib/qumcq.h"
#include "questionnairelib/qumcqgrid.h"
#include "questionnairelib/qumcqgriddouble.h"
#include "questionnairelib/qumcqgridsingleboolean.h"
#include "questionnairelib/qumultipleresponse.h"
#include "questionnairelib/qupage.h"
#include "questionnairelib/quphoto.h"
#include "questionnairelib/qupickerinline.h"
#include "questionnairelib/qupickerpopup.h"
#include "questionnairelib/quslider.h"
#include "questionnairelib/quspacer.h"
#include "questionnairelib/quspinboxdouble.h"
#include "questionnairelib/quspinboxinteger.h"
#include "questionnairelib/qutext.h"
#include "questionnairelib/qutextedit.h"
#include "questionnairelib/quthermometer.h"
#include "widgets/adjustablepie.h"
#include "widgets/aspectratiopixmap.h"
#include "widgets/basewidget.h"
#include "widgets/canvaswidget.h"
#include "widgets/clickablelabelnowrap.h"
#include "widgets/clickablelabelwordwrapwide.h"
#include "widgets/fixedareahfwtestwidget.h"
#include "widgets/fixedaspectratiohfwtestwidget.h"
#include "widgets/fixednumblockshfwtestwidget.h"
#include "widgets/horizontalline.h"
#include "widgets/imagebutton.h"
#include "widgets/labelwordwrapwide.h"
#include "widgets/svgwidgetclickable.h"
#include "widgets/thermometer.h"
#include "widgets/verticalline.h"
#include "widgets/verticalscrollarea.h"


const QString SHORT_TEXT("hello world");

const QString& sampleText(const bool long_text)
{
    return long_text ? TextConst::LOREM_IPSUM_1 : SHORT_TEXT;
}

WidgetTestMenu::WidgetTestMenu(CamcopsApp& app) :
    MenuWindow(app, uifunc::iconFilename(uiconst::CBS_SPANNER))

{
    const bool mandatory = true;

    FieldRef::GetterFunction getter1
        = std::bind(&WidgetTestMenu::dummyGetter1, this);
    FieldRef::SetterFunction setter1 = std::bind(
        &WidgetTestMenu::dummySetter1, this, std::placeholders::_1
    );
    FieldRef::GetterFunction getter2
        = std::bind(&WidgetTestMenu::dummyGetter2, this);
    FieldRef::SetterFunction setter2 = std::bind(
        &WidgetTestMenu::dummySetter2, this, std::placeholders::_1
    );
    m_fieldref_1 = FieldRefPtr(new FieldRef(getter1, setter1, mandatory));
    m_fieldref_2 = FieldRefPtr(new FieldRef(getter2, setter2, mandatory));

    m_blob = QSharedPointer<Blob>(new Blob(app, app.db()));  // specimen BLOB
    m_fieldref_blob = BlobFieldRefPtr(new BlobFieldRef(m_blob, true, true));
    // ... disable_creation_warning = true

    m_options_1.append(NameValuePair("Option A1", 1));
    m_options_1.append(NameValuePair("Option A2", 2));
    m_options_1.append(NameValuePair("Option A3", 3));

    m_options_2.append(NameValuePair("Option B1", 1));
    m_options_2.append(NameValuePair("Option B2", 2));

    m_options_3.append(NameValuePair("Option C1", 1));
    m_options_3.append(
        NameValuePair("Option C2 " + TextConst::LOREM_IPSUM_1, 2)
    );
    m_options_3.append(NameValuePair("Option C3", 3));
}

QString WidgetTestMenu::title() const
{
    return tr("Widget tests");
}

void WidgetTestMenu::makeItems()
{
    const bool qutext_bold = false;

    const QSizePolicy fixed_fixed(QSizePolicy::Fixed, QSizePolicy::Fixed);
    const QSizePolicy expand_expand(
        QSizePolicy::Expanding, QSizePolicy::Expanding
    );
    const QSizePolicy expand_fixed_hfw
        = sizehelpers::expandingFixedHFWPolicy();
    // UiFunc::horizExpandingPreferredHFWPolicy();

    m_items = {
        // --------------------------------------------------------------------
        MenuItem("Qt widgets").setLabelOnly(),
        // --------------------------------------------------------------------
        MenuItem(
            "QLabel (size policy = Fixed, Fixed / short / no word wrap)",
            std::bind(
                &WidgetTestMenu::testQLabel, this, fixed_fixed, false, false
            )
        ),
        MenuItem(
            "QLabel (size policy = Fixed, Fixed / long / no word wrap)",
            std::bind(
                &WidgetTestMenu::testQLabel, this, fixed_fixed, true, false
            )
        ),
        MenuItem(
            "QLabel (size policy = Fixed, Fixed / long / word wrap)",
            std::bind(
                &WidgetTestMenu::testQLabel, this, fixed_fixed, true, true
            )
        ),
        MenuItem(
            "QLabel (size policy = Expanding, Expanding / short / no word "
            "wrap)",
            std::bind(
                &WidgetTestMenu::testQLabel, this, expand_expand, false, false
            )
        ),
        MenuItem(
            "QLabel (size policy = Expanding, Expanding / long / no word "
            "wrap)",
            std::bind(
                &WidgetTestMenu::testQLabel, this, expand_expand, true, false
            )
        ),
        MenuItem(
            "QLabel (size policy = Expanding, Expanding / long / word wrap)",
            std::bind(
                &WidgetTestMenu::testQLabel, this, expand_expand, true, true
            )
        ),
        MenuItem(
            "QLabel (size policy = Expanding, Fixed, heightForWidth / short / "
            "no word wrap)",
            std::bind(
                &WidgetTestMenu::testQLabel,
                this,
                expand_fixed_hfw,
                false,
                false
            )
        ),
        MenuItem(
            "QLabel (size policy = Expanding, Fixed, heightForWidth / long / "
            "no word wrap)",
            std::bind(
                &WidgetTestMenu::testQLabel,
                this,
                expand_fixed_hfw,
                true,
                false
            )
        ),
        MenuItem(
            "QLabel (size policy = Expanding, Fixed, heightForWidth / long / "
            "word wrap)",
            std::bind(
                &WidgetTestMenu::testQLabel, this, expand_fixed_hfw, true, true
            )
        ),
        MenuItem(
            "QPushButton (size policy = Fixed, Fixed)",
            std::bind(&WidgetTestMenu::testQPushButton, this, fixed_fixed)
        ),
        MenuItem(
            "QPushButton (size policy = Expanding, Expanding)",
            std::bind(&WidgetTestMenu::testQPushButton, this, expand_expand)
        ),

        // --------------------------------------------------------------------
        MenuItem("Low-level widgets").setLabelOnly(),
        // --------------------------------------------------------------------
        MenuItem(
            "AdjustablePie (1)",
            std::bind(&WidgetTestMenu::testAdjustablePie, this, 1, true)
        ),
        MenuItem(
            "AdjustablePie (2)",
            std::bind(&WidgetTestMenu::testAdjustablePie, this, 2, true)
        ),
        MenuItem(
            "AdjustablePie (3, don't rotate labels)",
            std::bind(&WidgetTestMenu::testAdjustablePie, this, 3, false)
        ),
        MenuItem(
            "AdjustablePie (3, rotate labels)",
            std::bind(&WidgetTestMenu::testAdjustablePie, this, 3, true)
        ),
        MenuItem(
            "AspectRatioPixmap (should maintain aspect ratio and resize from "
            "0 to its intrinsic size)",
            std::bind(&WidgetTestMenu::testAspectRatioPixmap, this)
        ),
        MenuItem(
            "BooleanWidget (appearance=CheckBlack)",
            std::bind(
                &WidgetTestMenu::testBooleanWidget,
                this,
                BooleanWidget::Appearance::CheckBlack,
                false
            )
        ),
        MenuItem(
            "BooleanWidget (appearance=CheckRed)",
            std::bind(
                &WidgetTestMenu::testBooleanWidget,
                this,
                BooleanWidget::Appearance::CheckRed,
                false
            )
        ),
        MenuItem(
            "BooleanWidget (appearance=Radio)",
            std::bind(
                &WidgetTestMenu::testBooleanWidget,
                this,
                BooleanWidget::Appearance::Radio,
                false
            )
        ),
        MenuItem(
            "BooleanWidget (appearance=Text, short text)",
            std::bind(
                &WidgetTestMenu::testBooleanWidget,
                this,
                BooleanWidget::Appearance::Text,
                false
            )
        ),
        MenuItem(
            "BooleanWidget (appearance=Text, long text)",
            std::bind(
                &WidgetTestMenu::testBooleanWidget,
                this,
                BooleanWidget::Appearance::Text,
                true
            )
        ),
        MenuItem(
            "CanvasWidget (allow_shrink=false)",
            std::bind(&WidgetTestMenu::testCanvasWidget, this, false)
        ),
        MenuItem(
            "CanvasWidget (allow_shrink=true)",
            std::bind(&WidgetTestMenu::testCanvasWidget, this, true)
        ),
        MenuItem(
            "ClickableLabelNoWrap (short text) (not generally used: no word "
            "wrap)",
            std::bind(&WidgetTestMenu::testClickableLabelNoWrap, this, false)
        ),
        MenuItem(
            "ClickableLabelNoWrap (long text) (not generally used: no word "
            "wrap)",
            std::bind(&WidgetTestMenu::testClickableLabelNoWrap, this, true)
        ),
        MenuItem(
            "ClickableLabelWordWrapWide (short text)",
            std::bind(
                &WidgetTestMenu::testClickableLabelWordWrapWide, this, false
            )
        ),
        MenuItem(
            "ClickableLabelWordWrapWide (long text)",
            std::bind(
                &WidgetTestMenu::testClickableLabelWordWrapWide, this, true
            )
        ),
        MenuItem(
            "FixedAreaHfwTestWidget",
            std::bind(&WidgetTestMenu::testFixedAreaHfwTestWidget, this)
        ),
        MenuItem(
            "FixedAspectRatioHfwTestWidget",
            std::bind(&WidgetTestMenu::testFixedAspectRatioHfwTestWidget, this)
        ),
        MenuItem(
            "FixedNumBlocksHfwTestWidget",
            std::bind(&WidgetTestMenu::testFixedNumBlocksHfwTestWidget, this)
        ),
        MenuItem(
            "HorizontalLine",
            std::bind(&WidgetTestMenu::testHorizontalLine, this)
        ),
        MenuItem(
            "ImageButton", std::bind(&WidgetTestMenu::testImageButton, this)
        ),
        MenuItem(
            "LabelWordWrapWide (short text)",
            std::bind(
                &WidgetTestMenu::testLabelWordWrapWide,
                this,
                false,
                true,
                false
            )
        ),
        MenuItem(
            "LabelWordWrapWide (long text) (within QVBoxLayout)",
            std::bind(
                &WidgetTestMenu::testLabelWordWrapWide,
                this,
                true,
                false,
                false
            )
        ),
        MenuItem(
            "LabelWordWrapWide (long text) (within VBoxLayoutHfw)",
            std::bind(
                &WidgetTestMenu::testLabelWordWrapWide, this, true, true, false
            )
        ),
        MenuItem(
            "LabelWordWrapWide (long text) (within VBoxLayoutHfw + icons)",
            std::bind(
                &WidgetTestMenu::testLabelWordWrapWide, this, true, true, true
            )
        ),
        MenuItem(
            "SvgWidgetClickable",
            std::bind(&WidgetTestMenu::testSvgWidgetClickable, this)
        ),
        MenuItem(
            "Thermometer", std::bind(&WidgetTestMenu::testThermometer, this)
        ),
        MenuItem(
            "VerticalLine", std::bind(&WidgetTestMenu::testVerticalLine, this)
        ),

        // --------------------------------------------------------------------
        MenuItem("Layouts and the like").setLabelOnly(),
        // --------------------------------------------------------------------
        MenuItem(
            "FlowLayout (containing fixed-size icons, left-align)",
            std::bind(
                &WidgetTestMenu::testFlowLayout, this, 5, false, Qt::AlignLeft
            )
        ),
        MenuItem(
            "FlowLayout (containing fixed-size icons, centre-align)",
            std::bind(
                &WidgetTestMenu::testFlowLayout,
                this,
                5,
                false,
                Qt::AlignCenter
            )
        ),
        MenuItem(
            "FlowLayout (containing fixed-size icons, right-align)",
            std::bind(
                &WidgetTestMenu::testFlowLayout, this, 5, false, Qt::AlignRight
            )
        ),
        MenuItem(
            "FlowLayout (containing word-wrapped text)",
            std::bind(
                &WidgetTestMenu::testFlowLayout, this, 5, true, Qt::AlignLeft
            )
        ),
        MenuItem(
            "FlowLayout (containing FixedNumBlocksHfwTestWidget)",
            std::bind(
                &WidgetTestMenu::testFlowLayoutFixedNumBlocksHfwTestWidget,
                this,
                4
            )
        ),
        MenuItem(
            "FlowLayout (containing mixture)",
            std::bind(&WidgetTestMenu::testFlowLayoutMixture, this)
        ),
        MenuItem(
            "BaseWidget (with short text)",
            std::bind(&WidgetTestMenu::testBaseWidget, this, false)
        ),
        MenuItem(
            "BaseWidget (with long text)",
            std::bind(&WidgetTestMenu::testBaseWidget, this, true)
        ),
        MenuItem(
            "VBoxLayout (either QVBoxLayout or VBoxLayoutHfw), "
            "with 2 x LabelWordWrapWide (short text)",
            std::bind(&WidgetTestMenu::testVBoxLayout, this, false)
        ),
        MenuItem(
            "VBoxLayout (either QVBoxLayout or VBoxLayoutHfw), "
            "with 2 x LabelWordWrapWide (long text)",
            std::bind(&WidgetTestMenu::testVBoxLayout, this, true)
        ),
        MenuItem(
            "HBoxLayoutHfw, icon-stretch-icon",
            std::bind(&WidgetTestMenu::testHBoxLayoutHfwStretch, this)
        ),
        MenuItem(
            "GridLayoutHfw (example 1: fixed-size icons and word-wrapping "
            "text)",
            std::bind(&WidgetTestMenu::testGridLayoutHfw, this, 1)
        ),
        MenuItem(
            "GridLayoutHfw (example 2: 4 x short text, an example with "
            "height-for-width items only)",
            std::bind(&WidgetTestMenu::testGridLayoutHfw, this, 2)
        ),
        MenuItem(
            "GridLayoutHfw (example 3: approximating QuMcqGrid)",
            std::bind(&WidgetTestMenu::testGridLayoutHfw, this, 3)
        ),
        MenuItem(
            "GridLayoutHfw (example 4: 3 x ImageButton, an example with "
            "no height-for-width items)",
            std::bind(&WidgetTestMenu::testGridLayoutHfw, this, 4)
        ),
        MenuItem(
            "GridLayoutHfw (example 5: fixed-size icons and a "
            "FixedNumBlocksHfwTestWidget)",
            std::bind(&WidgetTestMenu::testGridLayoutHfw, this, 5)
        ),
        MenuItem(
            "VerticalScrollArea (QVBoxLayout, fixed-size icons)",
            std::bind(&WidgetTestMenu::testVerticalScrollAreaSimple, this)
        ),
        MenuItem(
            "VerticalScrollArea (VBoxLayout, short text)",
            std::bind(
                &WidgetTestMenu::testVerticalScrollAreaComplex, this, false
            )
        ),
        MenuItem(
            "VerticalScrollArea (VBoxLayout, long text)",
            std::bind(
                &WidgetTestMenu::testVerticalScrollAreaComplex, this, true
            )
        ),
        MenuItem(
            "VerticalScrollArea (FixedAreaHfwTestWidget)",
            std::bind(
                &WidgetTestMenu::testVerticalScrollAreaFixedAreaHfwWidget, this
            )
        ),
        MenuItem(
            "VerticalScrollArea (AspectRatioPixmap)",
            std::bind(
                &WidgetTestMenu::testVerticalScrollAreaAspectRatioPixmap, this
            )
        ),
        MenuItem(
            "VerticalScrollArea (GridLayout)",
            std::bind(&WidgetTestMenu::testVerticalScrollGridLayout, this)
        ),

        MenuItem("Large-scale widgets").setLabelOnly(),
        MenuItem("MenuItem", std::bind(&WidgetTestMenu::testMenuItem, this)),
        MenuItem(
            "QuestionnaireHeader",
            std::bind(&WidgetTestMenu::testQuestionnaireHeader, this)
        ),
        MenuItem(
            "Empty questionnaire (short title)",
            std::bind(&WidgetTestMenu::testQuestionnaire, this, false, false)
        ),
        MenuItem(
            "Empty questionnaire (long title)",
            std::bind(&WidgetTestMenu::testQuestionnaire, this, true, false)
        ),
        MenuItem(
            "Empty questionnaire (long title + as OpenableWidget)",
            std::bind(&WidgetTestMenu::testQuestionnaire, this, true, true)
        ),
        /*
        MenuItem(
            "Dummy ACE-III [will CRASH as no patient; layout testing only]"),
            std::bind(&WidgetTestMenu::testAce3, this)
        ),
        */

        // --------------------------------------------------------------------
        MenuItem("Questionnaire element widgets").setLabelOnly(),
        // --------------------------------------------------------------------
        MenuItem(
            "QuAudioPlayer",
            std::bind(&WidgetTestMenu::testQuAudioPlayer, this)
        ),
        MenuItem(
            "QuBoolean (as_text_button=false, short text)",
            std::bind(
                &WidgetTestMenu::testQuBoolean, this, false, false, false
            )
        ),
        MenuItem(
            "QuBoolean (as_text_button=false, short text, "
            "false_appears_blank)",
            std::bind(&WidgetTestMenu::testQuBoolean, this, false, false, true)
        ),
        MenuItem(
            "QuBoolean (as_text_button=false, long text)",
            std::bind(&WidgetTestMenu::testQuBoolean, this, false, true, false)
        ),
        MenuItem(
            "QuBoolean (as_text_button=true, short text)",
            std::bind(&WidgetTestMenu::testQuBoolean, this, true, false, false)
        ),
        MenuItem(
            "QuBoolean (as_text_button=true, long text)",
            std::bind(&WidgetTestMenu::testQuBoolean, this, true, true, false)
        ),
        MenuItem("QuButton", std::bind(&WidgetTestMenu::testQuButton, this)),
        MenuItem("QuCanvas", std::bind(&WidgetTestMenu::testQuCanvas, this)),
        MenuItem(
            "QuCountdown (loud)",
            std::bind(&WidgetTestMenu::testQuCountdown, this, 10, 100)
        ),
        MenuItem(
            "QuCountdown (quiet)",
            std::bind(&WidgetTestMenu::testQuCountdown, this, 10, 10)
        ),
        MenuItem(
            "QuDateTime", std::bind(&WidgetTestMenu::testQuDateTime, this)
        ),
        MenuItem(
            "QuDateTime (limited to 20th century)",
            std::bind(&WidgetTestMenu::testQuDateTimeLimited, this)
        ),
        MenuItem(
            "QuDiagnosticCode (NB iffy display if you select one!)",
            std::bind(&WidgetTestMenu::testQuDiagnosticCode, this)
        ),
        MenuItem(
            "QuHeading (short text)",
            std::bind(&WidgetTestMenu::testQuHeading, this, false)
        ),
        MenuItem(
            "QuHeading (long text)",
            std::bind(&WidgetTestMenu::testQuHeading, this, true)
        ),
        MenuItem(
            "QuHorizontalLine",
            std::bind(&WidgetTestMenu::testQuHorizontalLine, this)
        ),
        MenuItem("QuImage", std::bind(&WidgetTestMenu::testQuImage, this)),
        MenuItem(
            "QuLineEdit", std::bind(&WidgetTestMenu::testQuLineEdit, this)
        ),
        MenuItem(
            "QuLineEditDouble",
            std::bind(&WidgetTestMenu::testQuLineEditDouble, this)
        ),
        MenuItem(
            "QuLineEditInteger",
            std::bind(&WidgetTestMenu::testQuLineEditInteger, this)
        ),
        MenuItem(
            "QuLineEditLongLong",
            std::bind(&WidgetTestMenu::testQuLineEditLongLong, this)
        ),
        MenuItem(
            "QuLineEditNHSNumber",
            std::bind(&WidgetTestMenu::testQuLineEditNHSNumber, this)
        ),
        MenuItem(
            "QuLineEditULongLong",
            std::bind(&WidgetTestMenu::testQuLineEditULongLong, this)
        ),
        MenuItem(
            "QuMCQ (horizontal=false, short text)",
            std::bind(&WidgetTestMenu::testQuMCQ, this, false, false, false)
        ),
        MenuItem(
            "QuMCQ (horizontal=false, long text)",
            std::bind(&WidgetTestMenu::testQuMCQ, this, false, true, false)
        ),
        MenuItem(
            "QuMCQ (horizontal=true, short text)",
            std::bind(&WidgetTestMenu::testQuMCQ, this, true, false, false)
        ),
        MenuItem(
            "QuMCQ (horizontal=true, long text)",
            std::bind(&WidgetTestMenu::testQuMCQ, this, true, true, false)
        ),
        MenuItem(
            "QuMCQ (horizontal=true, short text, as text button)",
            std::bind(&WidgetTestMenu::testQuMCQ, this, true, false, true)
        ),
        MenuItem(
            "QuMCQGrid (expand=false, example=1)",
            std::bind(&WidgetTestMenu::testQuMCQGrid, this, false, 1)
        ),
        MenuItem(
            "QuMCQGrid (expand=true, example=1)",
            std::bind(&WidgetTestMenu::testQuMCQGrid, this, true, 1)
        ),
        MenuItem(
            "QuMCQGrid (expand=true, example=2)",
            std::bind(&WidgetTestMenu::testQuMCQGrid, this, true, 2)
        ),
        MenuItem(
            "QuMCQGrid (expand=true, example=3)",
            std::bind(&WidgetTestMenu::testQuMCQGrid, this, true, 3)
        ),
        MenuItem(
            "QuMCQGridDouble (expand=false)",
            std::bind(&WidgetTestMenu::testQuMCQGridDouble, this, false)
        ),
        MenuItem(
            "QuMCQGridDouble (expand=true)",
            std::bind(&WidgetTestMenu::testQuMCQGridDouble, this, true)
        ),
        MenuItem(
            "QuMCQGridSingleBoolean (expand=false)",
            std::bind(&WidgetTestMenu::testQuMCQGridSingleBoolean, this, false)
        ),
        MenuItem(
            "QuMCQGridSingleBoolean (expand=true)",
            std::bind(&WidgetTestMenu::testQuMCQGridSingleBoolean, this, true)
        ),
        MenuItem(
            "QuMultipleResponse (horizontal=false, short text)",
            std::bind(
                &WidgetTestMenu::testQuMultipleResponse, this, false, false
            )
        ),
        MenuItem(
            "QuMultipleResponse (horizontal=false, long text)",
            std::bind(
                &WidgetTestMenu::testQuMultipleResponse, this, false, true
            )
        ),
        MenuItem(
            "QuMultipleResponse (horizontal=true, short text)",
            std::bind(
                &WidgetTestMenu::testQuMultipleResponse, this, true, false
            )
        ),
        MenuItem(
            "QuMultipleResponse (horizontal=true, long text)",
            std::bind(
                &WidgetTestMenu::testQuMultipleResponse, this, true, true
            )
        ),
        // Not yet fixed:
        // - widget pops up in modal window
        // - camera then gets opened in window belonging to main window
        //   ... but its UI input is blocked, so we get nowhere
        //MenuItem("QuPhoto",
        //         std::bind(&WidgetTestMenu::testQuPhoto, this)),
        MenuItem(
            "QuPickerInline",
            std::bind(&WidgetTestMenu::testQuPickerInline, this)
        ),
        MenuItem(
            "QuPickerPopup",
            std::bind(&WidgetTestMenu::testQuPickerPopup, this)
        ),
        MenuItem(
            "QuSlider (horizontal=false)",
            std::bind(&WidgetTestMenu::testQuSlider, this, false)
        ),
        MenuItem(
            "QuSlider (horizontal=true)",
            std::bind(&WidgetTestMenu::testQuSlider, this, true)
        ),
        MenuItem("QuSpacer", std::bind(&WidgetTestMenu::testQuSpacer, this)),
        MenuItem(
            "QuSpinBoxDouble",
            std::bind(&WidgetTestMenu::testQuSpinBoxDouble, this)
        ),
        MenuItem(
            "QuSpinBoxInteger",
            std::bind(&WidgetTestMenu::testQuSpinBoxInteger, this)
        ),
        MenuItem(
            "QuText (short text)",
            std::bind(&WidgetTestMenu::testQuText, this, false, qutext_bold)
        ),
        MenuItem(
            "QuText (long text)",
            std::bind(&WidgetTestMenu::testQuText, this, true, qutext_bold)
        ),
        MenuItem(
            "QuTextEdit", std::bind(&WidgetTestMenu::testQuTextEdit, this)
        ),
        MenuItem(
            "QuThermometer",
            std::bind(&WidgetTestMenu::testQuThermometer, this)
        ),

        // --------------------------------------------------------------------
        MenuItem("Graphs").setLabelOnly(),
        // --------------------------------------------------------------------
        MenuItem(
            "Test QCustomPlot #1: y = x<sup>2</sup>",
            std::bind(&WidgetTestMenu::testQCustomPlot1, this)
        ),
        MenuItem(
            "Test QCustomPlot #2: date axis",
            std::bind(&WidgetTestMenu::testQCustomPlot2, this)
        ),

    };
}

QVariant WidgetTestMenu::dummyGetter1() const
{
    return m_dummy_value_1;
}

bool WidgetTestMenu::dummySetter1(const QVariant& value)
{
    const bool changed = (value != m_dummy_value_1);
    if (changed) {
        m_dummy_value_1 = value;
    }
    return changed;
}

QVariant WidgetTestMenu::dummyGetter2() const
{
    return m_dummy_value_2;
}

bool WidgetTestMenu::dummySetter2(const QVariant& value)
{
    const bool changed = (value != m_dummy_value_2);
    if (changed) {
        m_dummy_value_2 = value;
    }
    return changed;
}

void WidgetTestMenu::dummyAction()
{
    uifunc::alert("Action!");
}

void WidgetTestMenu::testQuestionnaireElement(QuElement* element)
{
    Questionnaire questionnaire(m_app);
    QWidget* widget = element->widget(&questionnaire);
    if (!widget) {
        uifunc::alert("Element failed to create a widget!");
        return;
    }
    layoutdumper::DumperConfig config;
    QString stylesheet(
        m_app.getSubstitutedCss(uiconst::CSS_CAMCOPS_QUESTIONNAIRE)
    );
    debugfunc::debugWidget(widget, false, false, config, true, &stylesheet);
}

// ============================================================================
// Qt widgets
// ============================================================================

void WidgetTestMenu::testQLabel(
    const QSizePolicy& policy, const bool long_text, const bool word_wrap
)
{
    auto widget = new QLabel(sampleText(long_text));
    widget->setWordWrap(word_wrap);
    widget->setSizePolicy(policy);
    debugfunc::debugWidget(widget);
}

void WidgetTestMenu::testQPushButton(const QSizePolicy& policy)
{
    auto widget = new QPushButton("Hello");
    widget->setSizePolicy(policy);
    // http://stackoverflow.com/questions/21367260/qt-making-a-qpushbutton-fill-layout-cell
    connect(widget, &QPushButton::clicked, this, &WidgetTestMenu::dummyAction);
    debugfunc::debugWidget(widget);
}

// ============================================================================
// Low-level widgets
// ============================================================================

void WidgetTestMenu::testAdjustablePie(const int n, const bool rotate_labels)
{
    auto pie = new AdjustablePie(n);
    const qreal prop = 1.0 / n;
    const QVector<qreal> proportions(n, prop);
    pie->setProportions(proportions);
    pie->setLabelRotation(rotate_labels);
    if (n == 1) {
        pie->setCentreLabel("Whole pie!");
    }
    for (int i = 0; i < n; ++i) {
        pie->setLabel(i, QString("Sector %1").arg(i));
    }
    debugfunc::debugWidget(pie);
}

void WidgetTestMenu::testAspectRatioPixmap()
{
    auto widget = new AspectRatioPixmap();
    const QPixmap pixmap
        = uifunc::getPixmap(uifunc::iconFilename(uiconst::ICON_CAMCOPS));
    widget->setPixmap(pixmap);
    debugfunc::debugWidget(widget);
}

void WidgetTestMenu::testBooleanWidget(
    const BooleanWidget::Appearance appearance, const bool long_text
)
{
    auto widget = new BooleanWidget();
    const bool big = true;
    const bool as_text_button
        = (appearance == BooleanWidget::Appearance::Text);
    widget->setAppearance(appearance);
    widget->setSize(big);
    widget->setValue(true, true);
    if (as_text_button) {
        widget->setText(
            long_text ? TextConst::LOREM_IPSUM_2 : "BooleanWidget"
        );
    }
    debugfunc::debugWidget(widget);
}

void WidgetTestMenu::testCanvasWidget(const bool allow_shrink)
{
    const QSize size(400, 400);
    auto widget = new CanvasWidget(size);
    const QImage img(size, QImage::Format_RGB32);
    widget->setImage(img);
    widget->setAllowShrink(allow_shrink);
    widget->clear(Qt::white);
    debugfunc::debugWidget(widget);
}

void WidgetTestMenu::testClickableLabelNoWrap(const bool long_text)
{
    auto widget = new ClickableLabelNoWrap(sampleText(long_text));
    connect(
        widget, &QAbstractButton::clicked, this, &WidgetTestMenu::dummyAction
    );
    debugfunc::debugWidget(widget);
}

void WidgetTestMenu::testClickableLabelWordWrapWide(const bool long_text)
{
    auto widget = new ClickableLabelWordWrapWide(sampleText(long_text));
    connect(
        widget, &QAbstractButton::clicked, this, &WidgetTestMenu::dummyAction
    );
    debugfunc::debugWidget(widget);
}

void WidgetTestMenu::testFixedAreaHfwTestWidget()
{
    auto widget = new FixedAreaHfwTestWidget();
    debugfunc::debugWidget(widget);
}

void WidgetTestMenu::testFixedAspectRatioHfwTestWidget()
{
    auto widget = new FixedAspectRatioHfwTestWidget();
    debugfunc::debugWidget(widget);
}

void WidgetTestMenu::testFixedNumBlocksHfwTestWidget()
{
    auto widget = new FixedNumBlocksHfwTestWidget();
    const bool use_hfw_layout = true;
    debugfunc::debugWidget(
        widget, false, true, layoutdumper::DumperConfig(), use_hfw_layout
    );
}

void WidgetTestMenu::testHorizontalLine()
{
    const int width = 4;
    auto widget = new HorizontalLine(width);
    widget->setStyleSheet("background-color: black;");
    debugfunc::debugWidget(widget);
}

void WidgetTestMenu::testImageButton()
{
    auto widget = new ImageButton(uiconst::CBS_ADD);
    debugfunc::debugWidget(widget);
}

void WidgetTestMenu::testLabelWordWrapWide(
    const bool long_text, const bool use_hfw_layout, const bool with_icons
)
{
    auto label = new LabelWordWrapWide(sampleText(long_text));
    QWidget* widget;
    if (with_icons) {
        widget = new QWidget();
        auto layout = new HBoxLayout(widget);
        layout->addWidget(new ImageButton(uiconst::CBS_ADD));
        layout->addWidget(label);
        layout->addWidget(new ImageButton(uiconst::CBS_ADD));
    } else {
        widget = label;
    }
    const bool set_background_by_name = false;
    const bool set_background_by_stylesheet = true;
    layoutdumper::DumperConfig config;
    debugfunc::debugWidget(
        widget,
        set_background_by_name,
        set_background_by_stylesheet,
        config,
        use_hfw_layout
    );
}

void WidgetTestMenu::testSvgWidgetClickable()
{
    auto widget = new SvgWidgetClickable();
    widget->setSvgFromString(graphicsfunc::TEST_SVG);
    debugfunc::debugWidget(widget);
}

void WidgetTestMenu::testThermometer()
{
    const QStringList left_strings{
        "row zero",
        "row one",
        "row two",
        "row three",
        "row four",
        "row five",
        "row six",
        "row seven",
        "row eight",
        "row nine",
        "row ten"};
    const QStringList right_strings{
        "10", "9", "8", "7", "6", "5", "4", "3", "2", "1", "0"};
    QVector<QPixmap> active_images;
    QVector<QPixmap> inactive_images;
    for (int i = 10; i >= 0; --i) {
        const QString active_filename = uifunc::resourceFilename(
            QString("distressthermometer/dt_sel_%1.png").arg(i)
        );
        const QString inactive_filename = uifunc::resourceFilename(
            QString("distressthermometer/dt_unsel_%1.png").arg(i)
        );
        active_images.append(uifunc::getPixmap(active_filename));
        inactive_images.append(uifunc::getPixmap(inactive_filename));
    }
    auto widget = new Thermometer(
        active_images,
        inactive_images,
        &left_strings,
        &right_strings,
        1,  // left_string_scale
        2,  // image_scale
        1,  // right_string_scale
        true,  // allow_deselection
        false,  // read_only
        true,  // rescale
        0.25,  // rescale_factor
        4,  // text_gap_px
        20,  // top image offset px
        nullptr  // parent
    );
    debugfunc::debugWidget(widget);
}

void WidgetTestMenu::testVerticalLine()
{
    const int width = 4;
    auto widget = new VerticalLine(width);
    widget->setStyleSheet("background-color: black;");
    debugfunc::debugWidget(widget);
}

// ============================================================================
// Layouts and the like
// ============================================================================

void WidgetTestMenu::testFlowLayout(
    const int n_icons, const bool text, const Qt::Alignment halign
)
{
    auto widget = new QWidget();
    widget->setSizePolicy(sizehelpers::preferredPreferredHFWPolicy());
    auto layout = new FlowLayoutHfw();
    layout->setHorizontalAlignmentOfContents(halign);
    widget->setLayout(layout);
    for (int i = 0; i < n_icons; ++i) {
        if (text) {
            layout->addWidget(new LabelWordWrapWide("A few words"));
        } else {
            QLabel* icon
                = uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD));
            layout->addWidget(icon);
        }
    }
    debugfunc::debugWidget(widget);
}

void WidgetTestMenu::testFlowLayoutFixedNumBlocksHfwTestWidget(const int n)
{
    auto widget = new QWidget();
    widget->setSizePolicy(sizehelpers::preferredPreferredHFWPolicy());
    auto layout = new FlowLayoutHfw();
    widget->setLayout(layout);
    for (int i = 0; i < n; ++i) {
        layout->addWidget(new FixedNumBlocksHfwTestWidget());
    }
    const bool use_hfw_layout = true;  // just for experimentation
    debugfunc::debugWidget(
        widget, false, false, layoutdumper::DumperConfig(), use_hfw_layout
    );
}

void WidgetTestMenu::testFlowLayoutMixture()
{
    auto widget = new QWidget();
    widget->setSizePolicy(sizehelpers::preferredPreferredHFWPolicy());
    auto layout = new FlowLayoutHfw();
    widget->setLayout(layout);
    for (int i = 0; i < 4; ++i) {
        layout->addWidget(new FixedAspectRatioHfwTestWidget());
        layout->addWidget(new FixedNumBlocksHfwTestWidget());
        layout->addWidget(new FixedAreaHfwTestWidget());
    }
    debugfunc::debugWidget(widget);
}

void WidgetTestMenu::testBaseWidget(const bool long_text)
{
    auto layout = new FlowLayoutHfw();
    layout->addWidget(new LabelWordWrapWide("Option Z1"));
    QString option2
        = long_text ? "Option Z2 " + TextConst::LOREM_IPSUM_2 : "Option Z2";
    layout->addWidget(new LabelWordWrapWide(option2));
    layout->addWidget(new LabelWordWrapWide("Option Z3"));
    auto widget = new BaseWidget();
    widget->setLayout(layout);
    debugfunc::debugWidget(widget);
}

void WidgetTestMenu::testVBoxLayout(const bool long_text)
{
    auto widget = new QWidget();
    auto layout = new VBoxLayout();
    widget->setLayout(layout);
    layout->addWidget(new LabelWordWrapWide(sampleText(long_text)));
    layout->addWidget(new LabelWordWrapWide(sampleText(long_text)));
    debugfunc::debugWidget(widget);
}

void WidgetTestMenu::testHBoxLayoutHfwStretch()
{
    auto widget = new QWidget();
    widget->setSizePolicy(sizehelpers::expandingExpandingHFWPolicy());
    auto layout = new HBoxLayoutHfw();
    widget->setLayout(layout);
    layout->addWidget(uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)
    ));
    layout->addStretch();
    layout->addWidget(uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)
    ));
    debugfunc::debugWidget(widget);
}

void WidgetTestMenu::testGridLayoutHfw(const int example)
{
    auto widget = new QWidget();
    auto grid = new GridLayoutHfw();
    widget->setLayout(grid);
    switch (example) {
        case 1:
        default:
            // row 0
            grid->addWidget(
                uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)),
                0,
                0
            );
            grid->addWidget(
                uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)),
                0,
                1
            );
            grid->addWidget(
                uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)),
                0,
                2
            );
            // row 1
            grid->addWidget(
                uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)),
                1,
                0
            );
            grid->addWidget(
                new LabelWordWrapWide(TextConst::LOREM_IPSUM_1), 1, 1
            );
            grid->addWidget(
                uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)),
                1,
                2
            );
            // row 2
            grid->addWidget(
                uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)),
                2,
                0
            );
            grid->addWidget(
                uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)),
                2,
                1
            );
            grid->addWidget(
                uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)),
                2,
                2
            );
            break;
        case 2:
            // row 0
            grid->addWidget(new LabelWordWrapWide(SHORT_TEXT), 0, 0);
            grid->addWidget(new LabelWordWrapWide(SHORT_TEXT), 0, 1);
            // row 1
            grid->addWidget(new LabelWordWrapWide(SHORT_TEXT), 1, 0);
            grid->addWidget(new LabelWordWrapWide(SHORT_TEXT), 1, 1);
            break;
        case 3:
            // spanning (first, as background)
            mcqfunc::addOptionBackground(grid, 0, 0, 4);
            mcqfunc::addVerticalLine(grid, 1, 3);
            // row 0
            grid->addWidget(new LabelWordWrapWide(SHORT_TEXT), 0, 2);
            grid->addWidget(new LabelWordWrapWide(SHORT_TEXT), 0, 3);
            grid->addWidget(new LabelWordWrapWide(SHORT_TEXT), 0, 4);
            // row 1
            grid->addWidget(new LabelWordWrapWide(SHORT_TEXT), 1, 0);
            grid->addWidget(
                uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)),
                1,
                2
            );
            grid->addWidget(
                uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)),
                1,
                3
            );
            grid->addWidget(
                uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)),
                1,
                4
            );
            // row 2
            grid->addWidget(new LabelWordWrapWide(SHORT_TEXT), 2, 0);
            grid->addWidget(
                uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)),
                2,
                2
            );
            grid->addWidget(
                uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)),
                2,
                3
            );
            grid->addWidget(
                uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)),
                2,
                4
            );
            break;
        case 4:
            // row 0
            grid->addWidget(new ImageButton(uiconst::CBS_ADD), 0, 0);
            // row 1
            grid->addWidget(new ImageButton(uiconst::CBS_ADD), 1, 0);
            // row 2
            grid->addWidget(new ImageButton(uiconst::CBS_ADD), 2, 0);
            break;
        case 5:
            // row 0
            grid->addWidget(
                uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)),
                0,
                0
            );
            grid->addWidget(
                uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)),
                0,
                1
            );
            grid->addWidget(
                uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)),
                0,
                2
            );
            // row 1
            grid->addWidget(
                uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)),
                1,
                0
            );
            grid->addWidget(new FixedNumBlocksHfwTestWidget(), 1, 1);
            grid->addWidget(
                uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)),
                1,
                2
            );
            // row 2
            grid->addWidget(
                uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)),
                2,
                0
            );
            grid->addWidget(
                uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)),
                2,
                1
            );
            grid->addWidget(
                uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)),
                2,
                2
            );
            break;
    }
    debugfunc::debugWidget(widget);
}

void WidgetTestMenu::testVerticalScrollAreaSimple()
{
    // QVBoxLayout and three simple fixed-size icons
    auto contentwidget = new QWidget();
    auto layout = new QVBoxLayout();  // simpler than VBoxLayoutHfw
    contentwidget->setLayout(layout);

    layout->addWidget(uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)
    ));
    layout->addWidget(uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)
    ));
    layout->addWidget(uifunc::iconWidget(uifunc::iconFilename(uiconst::CBS_ADD)
    ));

    auto scrollwidget = new VerticalScrollArea();
    scrollwidget->setWidget(contentwidget);
    debugfunc::debugWidget(scrollwidget);
}

void WidgetTestMenu::testVerticalScrollAreaComplex(const bool long_text)
{
    // VBoxLayout (i.e. likely VBoxLayoutHfw) and two word-wrapping labels
    auto contentwidget = new BaseWidget();
    auto layout = new VBoxLayout();
    contentwidget->setLayout(layout);

    layout->addWidget(new LabelWordWrapWide(sampleText(long_text)));
    layout->addWidget(new LabelWordWrapWide(sampleText(long_text)));

    auto scrollwidget = new VerticalScrollArea();
    scrollwidget->setWidget(contentwidget);
    debugfunc::debugWidget(scrollwidget);
}

void WidgetTestMenu::testVerticalScrollAreaFixedAreaHfwWidget()
{
    auto contentwidget = new FixedAreaHfwTestWidget();

    auto scrollwidget = new VerticalScrollArea();
    scrollwidget->setWidget(contentwidget);
    debugfunc::debugWidget(scrollwidget);
}

void WidgetTestMenu::testVerticalScrollAreaAspectRatioPixmap()
{
    auto contentwidget = new AspectRatioPixmap();
    QPixmap pixmap
        = uifunc::getPixmap(uifunc::iconFilename(uiconst::ICON_CAMCOPS));
    contentwidget->setPixmap(pixmap);

    auto scrollwidget = new VerticalScrollArea();
    scrollwidget->setWidget(contentwidget);
    debugfunc::debugWidget(scrollwidget);
}

void WidgetTestMenu::testVerticalScrollGridLayout()
{
    auto contentwidget = new BaseWidget();
    auto layout = new GridLayoutHfw();
    contentwidget->setLayout(layout);

    const bool long_text = true;
    QPixmap pixmap
        = uifunc::getPixmap(uifunc::iconFilename(uiconst::ICON_CAMCOPS));

    layout->addWidget(new LabelWordWrapWide(sampleText(long_text)), 0, 1);
    layout->addWidget(new LabelWordWrapWide(sampleText(long_text)), 0, 2);
    layout->addWidget(new LabelWordWrapWide(sampleText(long_text)), 1, 0);
    layout->addWidget(new AspectRatioPixmap(&pixmap), 1, 1);
    layout->addWidget(new AspectRatioPixmap(&pixmap), 1, 2);
    layout->addWidget(new LabelWordWrapWide(sampleText(long_text)), 2, 0);
    layout->addWidget(new AspectRatioPixmap(&pixmap), 2, 1);
    layout->addWidget(new AspectRatioPixmap(&pixmap), 2, 2);

    auto scrollwidget = new VerticalScrollArea();
    scrollwidget->setWidget(contentwidget);
    debugfunc::debugWidget(scrollwidget);
}

// ============================================================================
// Large-scale widgets
// ============================================================================

void WidgetTestMenu::testMenuItem()
{
    const MenuItem item = MAKE_TASK_MENU_ITEM("ace3", m_app);
    QWidget* widget = item.rowWidget(m_app);
    debugfunc::debugWidget(widget);
}

void WidgetTestMenu::testQuestionnaireHeader()
{
    auto widget = new QuestionnaireHeader(
        nullptr,
        TextConst::LOREM_IPSUM_1,
        false,
        true,
        false,
        cssconst::QUESTIONNAIRE_BACKGROUND_CONFIG
    );
    widget->setStyleSheet(
        m_app.getSubstitutedCss(uiconst::CSS_CAMCOPS_QUESTIONNAIRE)
    );
    debugfunc::debugWidget(widget);
}

void WidgetTestMenu::testQuestionnaire(
    const bool long_title, const bool as_openable_widget
)
{
    QuPagePtr page(new QuPage());
    page->addElement(new QuText(TextConst::LOREM_IPSUM_1));
    page->setTitle(
        long_title ? TextConst::LOREM_IPSUM_1
                   : "Reasonably long title with several words"
    );
    auto widget = new Questionnaire(m_app, {page});
    if (as_openable_widget) {
        m_app.openSubWindow(widget);
    } else {
        widget->build();
        debugfunc::debugWidget(widget, false, false);
    }
}

/*
void WidgetTestMenu::testAce3()
{
    TaskPtr task(new Ace3(m_app, m_app.db()));
    OpenableWidget* widget = task->editor();
    if (!widget) {
        uifunc::alert("ACE-3: no editor provided!");
        return;
    }
    widget->build();
    DebugFunc::debugWidget(widget);
}
*/


// ============================================================================
// Questionnaire element widgets
// ============================================================================

void WidgetTestMenu::testQuAudioPlayer()
{
    QuAudioPlayer element(uiconst::DEMO_SOUND_URL_1);
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuBoolean(
    const bool as_text_button,
    const bool long_text,
    const bool false_appears_blank
)
{
    QuBoolean element(sampleText(long_text), m_fieldref_1);
    element.setAsTextButton(as_text_button);
    element.setFalseAppearsBlank(false_appears_blank);
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuButton()
{
    QuButton element(
        "QuButton", std::bind(&WidgetTestMenu::dummyAction, this)
    );
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuCanvas()
{
    QuCanvas element(m_fieldref_blob);
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuCountdown(const int time_s, const int volume)
{
    QuCountdown element(time_s);

    Questionnaire questionnaire(m_app);
    QWidget* widget = element.widget(&questionnaire);
    if (!widget) {
        uifunc::alert("Element failed to create a widget!");
        return;
    }
    element.setVolume(volume);
    layoutdumper::DumperConfig config;
    QString stylesheet(
        m_app.getSubstitutedCss(uiconst::CSS_CAMCOPS_QUESTIONNAIRE)
    );
    debugfunc::debugWidget(widget, false, false, config, true, &stylesheet);
}

void WidgetTestMenu::testQuDateTime()
{
    QuDateTime element(m_fieldref_1);
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuDateTimeLimited()
{
    QuDateTime element(m_fieldref_1);
    element.setMinimumDate(QDate(1900, 1, 1));
    element.setMaximumDate(QDate(1999, 12, 31));
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuDiagnosticCode()
{
    QSharedPointer<Icd10> icd10 = QSharedPointer<Icd10>(new Icd10(m_app));
    QuDiagnosticCode element(icd10, m_fieldref_1, m_fieldref_2);
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuHeading(const bool long_text)
{
    QuHeading element(sampleText(long_text));
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuHorizontalLine()
{
    QuHorizontalLine element;
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuImage()
{
    QuImage element(uifunc::iconFilename(uiconst::ICON_CAMCOPS));
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuLineEdit()
{
    QuLineEdit element(m_fieldref_1);
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuLineEditDouble()
{
    QuLineEditDouble element(m_fieldref_1);
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuLineEditInteger()
{
    QuLineEditInteger element(m_fieldref_1);
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuLineEditLongLong()
{
    QuLineEditInt64 element(m_fieldref_1);
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuLineEditNHSNumber()
{
    QuLineEditNHSNumber element(m_fieldref_1);
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuLineEditULongLong()
{
    QuLineEditUInt64 element(m_fieldref_1);
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuMCQ(
    const bool horizontal, const bool long_text, const bool as_text_button
)
{
    QuMcq element(m_fieldref_1, long_text ? m_options_3 : m_options_1);
    element.setHorizontal(horizontal);
    element.setAsTextButton(as_text_button);
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuMCQGrid(const bool expand, const int example)
{
    const QString q2 = example == 1 ? "Question 2" : TextConst::LOREM_IPSUM_1;
    QVector<QuestionWithOneField> question_field_pairs{
        QuestionWithOneField(m_fieldref_1, "Question 1"),
        QuestionWithOneField(m_fieldref_2, q2),
    };
    QuMcqGrid element(question_field_pairs, m_options_1);
    element.setExpand(expand);
    switch (example) {
        case 1:
        case 2:
        default:
            break;
        case 3:
            element.setTitle("MCQ 2 title; " + TextConst::LOREM_IPSUM_2);
            break;
    }
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuMCQGridDouble(const bool expand)
{
    QVector<QuestionWithTwoFields> question_field_pairs{
        QuestionWithTwoFields("Question 1", m_fieldref_1, m_fieldref_2),
        QuestionWithTwoFields(
            "Question 2 " + TextConst::LOREM_IPSUM_1,
            m_fieldref_1,
            m_fieldref_2
        ),
    };
    QuMcqGridDouble element(question_field_pairs, m_options_1, m_options_2);
    element.setExpand(expand);
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuMCQGridSingleBoolean(const bool expand)
{
    QVector<QuestionWithTwoFields> question_field_pairs{
        QuestionWithTwoFields("Question 1", m_fieldref_1, m_fieldref_2),
        QuestionWithTwoFields(
            "Question 2 " + TextConst::LOREM_IPSUM_1,
            m_fieldref_1,
            m_fieldref_2
        ),
    };
    QuMcqGridSingleBoolean element(
        question_field_pairs, m_options_1, "boolean"
    );
    element.setExpand(expand);
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuMultipleResponse(
    const bool horizontal, const bool long_text
)
{
    QVector<QuestionWithOneField> question_field_pairs{
        QuestionWithOneField(m_fieldref_1, "Question 1"),
        QuestionWithOneField(
            m_fieldref_2, long_text ? TextConst::LOREM_IPSUM_1 : "Question 2"
        ),
    };
    QuMultipleResponse element(question_field_pairs);
    element.setHorizontal(horizontal);
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuPhoto()
{
    QuPhoto element(m_fieldref_blob);
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuPickerInline()
{
    QuPickerInline element(m_fieldref_1, m_options_3);
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuPickerPopup()
{
    QuPickerPopup element(m_fieldref_1, m_options_3);
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuSlider(const bool horizontal)
{
    QuSlider element(m_fieldref_1, 0, 10, 1);
    element.setHorizontal(horizontal);
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuSpacer()
{
    QuSpacer element;
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuSpinBoxDouble()
{
    QuSpinBoxDouble element(m_fieldref_1, 0.0, 10.0, 2);
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuSpinBoxInteger()
{
    QuSpinBoxInteger element(m_fieldref_1, 0, 10);
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuText(const bool long_text, const bool bold)
{
    QuText element(sampleText(long_text));
    if (bold) {
        element.setBold(true);
    }
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuTextEdit()
{
    QuTextEdit element(m_fieldref_1);
    testQuestionnaireElement(&element);
}

void WidgetTestMenu::testQuThermometer()
{
    QVector<QuThermometerItem> thermometer_items;
    for (int i = 0; i <= 10; ++i) {
        QString text = QString::number(i);
        QuThermometerItem item(
            uifunc::resourceFilename(
                QString("distressthermometer/dt_sel_%1.png").arg(i)
            ),
            uifunc::resourceFilename(
                QString("distressthermometer/dt_unsel_%1.png").arg(i)
            ),
            text,
            i
        );
        thermometer_items.append(item);
    }
    QuThermometer element(m_fieldref_1, thermometer_items);
    element.setRescale(true, 0.4);
    testQuestionnaireElement(&element);
}

// ============================================================================
// Graphs
// ============================================================================

QCustomPlot* WidgetTestMenu::makeQCustomPlotOrWarn()
{
    auto p = new QCustomPlot();
    if (!p) {
        qWarning() << "Unable to create QCustomPlot";
    }
    return p;
}

void WidgetTestMenu::showPlot(QCustomPlot* p, const QSize& minsize)
{
    const bool set_background_by_name = false;
    const bool set_background_by_stylesheet = false;
    const bool use_hfw_layout = false;

    p->setMinimumSize(minsize);
    auto dlg = new DebugDialog(
        this,
        p,
        set_background_by_name,
        set_background_by_stylesheet,
        layoutdumper::DumperConfig(),
        use_hfw_layout
    );  // memory management now by Qt

    dlg->setModal(true);
    dlg->show();
}

void WidgetTestMenu::testQCustomPlot1()
{
    // From https://www.qcustomplot.com/index.php/tutorials/basicplotting
    auto plot = makeQCustomPlotOrWarn();
    if (!plot) {
        return;
    }

    // generate some data:
    const int n = 101;
    QVector<double> x(n), y(n);
    for (int i = 0; i < n; ++i) {
        x[i] = i / 50.0 - 1;  // x goes from -1 to 1
        y[i] = x[i] * x[i];  // let's plot a quadratic function
    }
    // create graph and assign data to it:
    plot->addGraph();
    plot->graph(0)->setData(x, y);
    // give the axes some labels:
    plot->xAxis->setLabel("x");
    plot->yAxis->setLabel("y");
    // set axes ranges, so we see all data:
    plot->xAxis->setRange(-1, 1);
    plot->yAxis->setRange(0, 1);
    plot->replot();

    // Show dialogue
    showPlot(plot);  // takes ownership
}

void WidgetTestMenu::testQCustomPlot2()
{
    // From https://www.qcustomplot.com/index.php/tutorials/basicplotting,
    // modified a bit:
    // - random number generation
    // - seconds since epoch

    auto plot = makeQCustomPlotOrWarn();
    if (!plot) {
        return;
    }
    QRandomGenerator rng(8);  // seed at creation

    // set locale to english, so we get english month names:
    plot->setLocale(QLocale(QLocale::English, QLocale::UnitedKingdom));
    // seconds of current time, we'll use it as starting point in time for
    // data:
    double now = QDateTime::currentDateTime().toSecsSinceEpoch();
    // create multiple graphs:
    const int ngraphs = 5;
    const int n = 250;
    for (int gi = 0; gi < ngraphs; ++gi) {
        plot->addGraph();
        QColor color(20 + 200 / 4.0 * gi, 70 * (1.6 - gi / 4.0), 150, 150);
        plot->graph()->setLineStyle(QCPGraph::lsLine);
        plot->graph()->setPen(QPen(color.lighter(200)));
        plot->graph()->setBrush(QBrush(color));
        // generate random walk data:
        QVector<QCPGraphData> timedata(n);
        for (int i = 0; i < n; ++i) {
            timedata[i].key = now + 24 * 3600 * i;  // units are seconds
            const double randval = rng.generateDouble() - 0.5;
            // ... range [-0.5, +0.5)
            if (i == 0) {
                timedata[i].value = (i / 50.0 + 1) * randval;
            } else {
                timedata[i].value = qFabs(timedata[i - 1].value)
                        * (1 + 0.02 / 4.0 * (4 - gi))
                    + (i / 50.0 + 1) * randval;
            }
        }
        plot->graph()->data()->set(timedata);
    }
    // configure bottom axis to show date instead of number:
    QSharedPointer<QCPAxisTickerDateTime> dateTicker(new QCPAxisTickerDateTime
    );
    dateTicker->setDateTimeFormat("d MMMM\nyyyy");
    plot->xAxis->setTicker(dateTicker);
    // configure left axis text labels:
    QSharedPointer<QCPAxisTickerText> textTicker(new QCPAxisTickerText);
    textTicker->addTick(10, "a bit\nlow");
    textTicker->addTick(50, "quite\nhigh");
    plot->yAxis->setTicker(textTicker);
    // set a more compact font size for bottom and left axis tick labels:
    plot->xAxis->setTickLabelFont(QFont(QFont().family(), 8));
    plot->yAxis->setTickLabelFont(QFont(QFont().family(), 8));
    // set axis labels:
    plot->xAxis->setLabel("Date");
    plot->yAxis->setLabel("Random wobbly lines value");
    // make top and right axes visible but without ticks and labels:
    plot->xAxis2->setVisible(true);
    plot->yAxis2->setVisible(true);
    plot->xAxis2->setTicks(false);
    plot->yAxis2->setTicks(false);
    plot->xAxis2->setTickLabels(false);
    plot->yAxis2->setTickLabels(false);
    // set axis ranges to show all data:
    plot->xAxis->setRange(now, now + 24 * 3600 * n - 1);
    plot->yAxis->setRange(0, 60);
    // show legend with slightly transparent background brush:
    plot->legend->setVisible(true);
    plot->legend->setBrush(QColor(255, 255, 255, 150));

    // Show dialogue
    showPlot(plot);  // takes ownership
}