Warning, /education/gcompris/src/core/GCDialog.qml is written in an unsupported language. File is not indexed.

0001 /* GCompris - GCDialog.qml
0002  *
0003  * SPDX-FileCopyrightText: 2014 Bruno Coudoin <bruno.coudoin@gcompris.net>
0004  *
0005  * Authors:
0006  *   Bruno Coudoin <bruno.coudoin@gcompris.net>
0007  *
0008  *   SPDX-License-Identifier: GPL-3.0-or-later
0009  */
0010 import QtQuick 2.12
0011 import GCompris 1.0
0012 
0013 /**
0014  * A QML component for GCompris dialogs.
0015  * @ingroup components
0016  *
0017  * Contains the following basic layout elements: Title (message), a GCompris
0018  * cancel button (GCButtonCancel) at the top right and two optional buttons.
0019  *
0020  * Can be conveniently instantiated dynamically in conjunction with
0021  * showMessageDialog from core.js.
0022  *
0023  * GCDialog should now be used wherever you'd use a QtQuick dialog. It has
0024  * been decided to implement dialogs ourselves in GCompris because of
0025  * missing translations of labels of Qt's standard buttons for some language
0026  * supported by GCompris, as well as integration problems on some OSes
0027  * (Sailfish OS).
0028  *
0029  * @inherit QtQuick.Item
0030  * @sa showMessageDialog
0031  */
0032 Rectangle {
0033     id: gcdialog
0034     color: "#B2808080"
0035     property int baseMargins: 5 * ApplicationInfo.ratio
0036 
0037     /**
0038      * type:string
0039      * Heading instruction text.
0040      */
0041     property alias message: instructionTxt.textIn
0042 
0043     /**
0044      * type:string
0045      * Label of the first button.
0046      */
0047     property alias button1Text: button1.text
0048 
0049     /**
0050      * type:string
0051      * Label of the second button.
0052      */
0053     property alias button2Text: button2.text
0054 
0055     /**
0056      * type:bool
0057      * Check is the dialog can be destroyed
0058      */
0059     property bool isDestructible: true
0060 
0061     /**
0062      * type:bool
0063      * Set to true after clicking on one of the options
0064      */
0065     property bool alreadyClicked: false
0066 
0067     /**
0068      * Emitted when the dialog should be started.
0069      *
0070      * Triggers fading in.
0071      */
0072     signal start
0073 
0074     /**
0075      * Emitted when the dialog should be stopped.
0076      *
0077      * Triggers fading out.
0078      */
0079     signal stop
0080 
0081     /**
0082      * Emitted when the dialog has stopped.
0083      */
0084     signal close
0085 
0086     /**
0087      * Emitted when the first button has been clicked.
0088      */
0089     signal button1Hit
0090 
0091     /**
0092      * Emitted when the second button has been clicked.
0093      */
0094     signal button2Hit
0095 
0096     /**
0097      * type:Component
0098      * Content component which holds the optional content
0099      * after instructionText
0100      */
0101     property Component content
0102 
0103     focus: true
0104     opacity: 0
0105 
0106     onVisibleChanged: {
0107         if(visible) {
0108             gcdialog.forceActiveFocus();
0109             parent.Keys.enabled = false;
0110         }
0111     }
0112 
0113     anchors {
0114         fill: parent
0115     }
0116 
0117     onStart: {
0118         opacity = 1;
0119         gcdialog.forceActiveFocus();
0120         parent.Keys.enabled = false;
0121         alreadyClicked = false;
0122     }
0123     onStop: {
0124         opacity = 0;
0125         parent.Keys.enabled = true;
0126         parent.forceActiveFocus();
0127     }
0128     onClose: {
0129         if(isDestructible)
0130             destroy();
0131     }
0132 
0133     Behavior on opacity { NumberAnimation { duration: 200 } }
0134     onOpacityChanged: opacity === 0 ? close() : null
0135 
0136     z: 1500
0137 
0138     MultiPointTouchArea {
0139         // Just to catch mouse events
0140         anchors.fill: parent
0141     }
0142 
0143     /* Message */
0144     Item {
0145         id: instruction
0146         anchors {
0147             horizontalCenter: parent.horizontalCenter
0148             top: parent.top
0149             topMargin: buttonCancel.height + 2 * gcdialog.baseMargins
0150             bottom: parent.bottom
0151             bottomMargin: gcdialog.baseMargins
0152         }
0153         width: parent.width * 0.8
0154 
0155         Rectangle {
0156             id: instructionTxtBg
0157             anchors.top: instruction.top
0158             width: parent.width
0159             height: instruction.height - button1.height * 3 - gcdialog.baseMargins * 3
0160             radius: gcdialog.baseMargins
0161             border.width: 2 * ApplicationInfo.ratio
0162             border.color: "white"
0163             color: "#EEEEEEEE"
0164 
0165             Flickable {
0166                 id: instructionFlick
0167                 flickDeceleration: 1500
0168                 anchors.fill: parent
0169                 anchors.margins: gcdialog.baseMargins
0170                 flickableDirection: Flickable.VerticalFlick
0171                 clip: true
0172                 contentHeight: instructionTxt.height + extraLoader.height + 15 * ApplicationInfo.ratio
0173 
0174                 GCText {
0175                     id: instructionTxt
0176                     fontSize: regularSize
0177                     color: "#191919"
0178                     anchors.horizontalCenter: parent.horizontalCenter
0179                     // need to remove the anchors (left and right) else sometimes text is hidden on the side
0180                     width: instructionFlick.width
0181                     wrapMode: TextEdit.WordWrap
0182                     textFormat: TextEdit.RichText
0183                     text: style + "<body>" + textIn + "</body>"
0184                     property string textIn
0185                     property string style: "<HEAD><STYLE type='text/css'>A {color: #191919;}</STYLE></HEAD>"
0186                 }
0187                 Loader {
0188                     id: extraLoader
0189                     anchors.top: instructionTxt.bottom
0190                     anchors.topMargin: gcdialog.baseMargins
0191                     active: gcdialog.content != null
0192                     sourceComponent: gcdialog.content
0193                     width: instructionFlick.width
0194                 }
0195             }
0196             // The scroll buttons
0197             GCButtonScroll {
0198                 id: scrollInstructions
0199                 opacity: 0.7
0200                 visible: instructionFlick.contentHeight > instructionFlick.height
0201                 anchors.right: parent.right
0202                 anchors.rightMargin: 5 * ApplicationInfo.ratio
0203                 anchors.bottom: parent.bottom
0204                 anchors.bottomMargin: 5 * ApplicationInfo.ratio
0205                 onUp: instructionFlick.flick(0, 1000)
0206                 onDown: instructionFlick.flick(0, -1000)
0207                 upVisible: instructionFlick.atYBeginning ? false : true
0208                 downVisible: instructionFlick.atYEnd ? false : true
0209             }
0210         }
0211 
0212         Rectangle {
0213             id: buttonSelector
0214             width: gcdialog.width
0215             height: button1.height + gcdialog.baseMargins * 2
0216             color: "#803ACAFF"
0217             visible: false
0218         }
0219 
0220         GCButton {
0221             id: button1
0222             width: parent.width
0223             height: (visible ? 60 : 30) * ApplicationInfo.ratio
0224             anchors {
0225                 horizontalCenter: parent.horizontalCenter
0226                 top: instructionTxtBg.bottom
0227                 topMargin: 10
0228             }
0229             theme: "highContrast"
0230             visible: text != ""
0231             property bool selected: false;
0232             enabled: !gcdialog.alreadyClicked
0233             onClicked: {
0234                 gcdialog.alreadyClicked = true;
0235                 gcdialog.button1Hit()
0236                 gcdialog.stop()
0237             }
0238         }
0239 
0240         GCButton {
0241             id: button2
0242             width: parent.width
0243             height: (visible ? 60 : 30) * ApplicationInfo.ratio
0244             anchors {
0245                 horizontalCenter: parent.horizontalCenter
0246                 top: button1.bottom
0247                 topMargin: 10
0248             }
0249             theme: "highContrast"
0250             visible: text != ""
0251             property bool selected: false;
0252             enabled: !gcdialog.alreadyClicked
0253             onClicked: {
0254                 gcdialog.alreadyClicked = true;
0255                 gcdialog.button2Hit()
0256                 gcdialog.stop()
0257             }
0258         }
0259 
0260         states: [
0261             State {
0262                 name: "button1Selected"
0263                 when: button1.selected
0264                 PropertyChanges {
0265                     target: buttonSelector
0266                     anchors.centerIn: button1
0267                     visible: true
0268                 }
0269             },
0270             State {
0271                 name: "button2Selected"
0272                 when: button2.selected
0273                 PropertyChanges {
0274                     target: buttonSelector
0275                     anchors.centerIn: button2
0276                     visible: true
0277                 }
0278             }
0279         ]
0280     }
0281 
0282     Keys.onEscapePressed: {
0283         buttonCancel.close();
0284     }
0285 
0286     Keys.onTabPressed: {
0287         return;
0288     }
0289 
0290     Keys.onPressed: {
0291         if(event.key === Qt.Key_Up || event.key === Qt.Key_Left) {
0292             if(button2.visible && !button1.selected && !button2.selected) {
0293                 button2.selected = true;
0294             } else if(button2.visible) {
0295                 button2.selected = !button2.selected;
0296                 button1.selected = !button1.selected;
0297             } else if(button1.visible) {
0298                 button1.selected = true;
0299             }
0300         }
0301         if(event.key === Qt.Key_Down || event.key === Qt.Key_Right) {
0302             if(button1.visible && !button1.selected && !button2.selected) {
0303                 button1.selected = true;
0304             } else if(button2.visible) {
0305                 button1.selected = !button1.selected;
0306                 button2.selected = !button2.selected;
0307             } else if(button1.visible) {
0308                 button1.selected = true;
0309             }
0310         }
0311         if(event.key === Qt.Key_Enter || event.key === Qt.Key_Return || event.key === Qt.Key_Space) {
0312             event.accepted = true;
0313             if(button1.selected) {
0314                 button1.clicked();
0315             } else if(button2.selected) {
0316                 button2.clicked();
0317             } else {
0318                 buttonCancel.close();
0319             }
0320         }
0321     }
0322 
0323     Keys.onReleased: {
0324         if(event.key === Qt.Key_Back) {
0325             buttonCancel.close();
0326             event.accepted = true;
0327         }
0328     }
0329 
0330     // The cancel button
0331     GCButtonCancel {
0332         id: buttonCancel
0333         anchors.margins: 5 * ApplicationInfo.ratio
0334         onClose: {
0335             if(button2.visible)
0336                 button2.clicked();
0337             else if(button1.visible)
0338                 button1.clicked();
0339             else
0340                 parent.stop();
0341         }
0342     }
0343 }