From 1df70118583e069bde41d03bc9753cef949b3e39 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Fri, 3 Aug 2018 14:21:05 +0200 Subject: Doc: tutorial Get Started with Qt Quick Task-number: QTBUG-68739 Change-Id: Ib14e4eb4c20583af2be9198539077f1be5ae471a Reviewed-by: Edward Welbourne Reviewed-by: Venugopal Shivashankar --- doc/config/qtdoc.qdocconf | 2 +- doc/src/getting-started/gettingstartedqml.qdoc | 1196 ++++------------------- doc/src/images/addalarms.png | Bin 0 -> 5231 bytes doc/src/images/alarms2.png | Bin 0 -> 24310 bytes doc/src/images/alarms3.png | Bin 0 -> 14194 bytes doc/src/images/detailscreen.png | Bin 0 -> 10657 bytes doc/src/images/mainscreen.png | Bin 0 -> 7056 bytes examples/tutorials/alarms/AlarmDelegate.qml | 142 +++ examples/tutorials/alarms/AlarmDialog.qml | 168 ++++ examples/tutorials/alarms/AlarmModel.qml | 152 +++ examples/tutorials/alarms/TumblerDelegate.qml | 62 ++ examples/tutorials/alarms/alarms.pro | 29 + examples/tutorials/alarms/main.cpp | 65 ++ examples/tutorials/alarms/main.qml | 86 ++ examples/tutorials/alarms/qml.qrc | 10 + examples/tutorials/alarms/qtquickcontrols2.conf | 5 + 16 files changed, 915 insertions(+), 1002 deletions(-) create mode 100644 doc/src/images/addalarms.png create mode 100644 doc/src/images/alarms2.png create mode 100644 doc/src/images/alarms3.png create mode 100644 doc/src/images/detailscreen.png create mode 100644 doc/src/images/mainscreen.png create mode 100644 examples/tutorials/alarms/AlarmDelegate.qml create mode 100644 examples/tutorials/alarms/AlarmDialog.qml create mode 100644 examples/tutorials/alarms/AlarmModel.qml create mode 100644 examples/tutorials/alarms/TumblerDelegate.qml create mode 100644 examples/tutorials/alarms/alarms.pro create mode 100644 examples/tutorials/alarms/main.cpp create mode 100644 examples/tutorials/alarms/main.qml create mode 100644 examples/tutorials/alarms/qml.qrc create mode 100644 examples/tutorials/alarms/qtquickcontrols2.conf diff --git a/doc/config/qtdoc.qdocconf b/doc/config/qtdoc.qdocconf index 623cf0d6..5a346f4f 100644 --- a/doc/config/qtdoc.qdocconf +++ b/doc/config/qtdoc.qdocconf @@ -88,7 +88,7 @@ exampledirs += \ excludedirs += \ ../src/snippets -examplesinstallpath = demos +examplesinstallpath = qhp.projects = QtDoc diff --git a/doc/src/getting-started/gettingstartedqml.qdoc b/doc/src/getting-started/gettingstartedqml.qdoc index cd6cedf1..f66f1a01 100644 --- a/doc/src/getting-started/gettingstartedqml.qdoc +++ b/doc/src/getting-started/gettingstartedqml.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -26,1063 +26,257 @@ ****************************************************************************/ /*! - \page gettingstartedqml.html + \example tutorials/gettingstartedqtquick \title Getting Started Programming with Qt Quick + \brief A tutorial for Qt Quick based on an alarms application + + This tutorial shows how to develop a simple alarm application as + an introduction to Qt Quick and Qt Quick Controls2. + + This application is similar to the alarm application usually + found on an Android phone. Its features let you enter, edit, + or delete alarms. An alarm can trigger on a given date, and you + can set it to repeat on a series of subsequent days. + + The main screen shows the list of saved alarms: + + \image mainscreen.png "Alarms application" + + The detail screen lets you edit or delete existing alarms: + + \image detailscreen.png "Detail screen" + + The dialog screen is used for adding new alarms. It pops up + when you click on the "+" RoundButton on the bottom of the main + screen: + + \image addalarms.png "Add alarms" + + The source files are located in the qtdoc repository. + You can either fetch the Qt 5 sources from the Qt Project, + or install them as part of Qt 5. The application is also available + in the example list of Qt Creator's Welcome mode. + + \section1 Creating the Alarms Project + + This section shows how to create the project in Qt Creator. It discusses + the files generated automatically by Qt Creator, and the two files + the programmer has to create in Qt Creator or some other editor. + The latter two files are included with the source code for this + tutorial. + + \section1 Qt Creator - Welcome to the world of \b QML, the declarative UI language. In this Getting - Started guide, we will create a simple text editor application using QML. - After reading this guide, you should be ready to develop your own applications - using QML and Qt C++. + Setting up a new project in Qt Creator is aided by a wizard that + guides you step-by-step through the project creation process. The + wizard prompts you to enter the settings needed for that particular + type of project and creates the project for you. + + To create the Alarms project, select \uicontrol{File} > + \uicontrol{New File or Project} > \uicontrol{Application} > + \uicontrol{Qt Quick Application - Empty} > \uicontrol{Choose}. + Type "alarms" in the \b{Name} field, and follow the instructions + of the wizard. - \section1 QML to Build User Interfaces + \image alarms2.png "Qt Creator New File or Project dialog" + + \image alarms3.png "Project Location" - The application we are building is a simple text editor that will load, save, - and perform some text manipulation. This guide will consist of two parts. The - first part will involve designing the application layout and behaviors using - declarative language in QML. For the second part, file loading and saving will - be implemented using Qt C++. Using - \l {The Meta-Object System}{Qt's Meta-Object System}, we can expose C++ functions - as properties that \l{QML Object Types}{QML object types} can use. Utilizing QML and Qt C++, we can - efficiently decouple the interface logic from the application logic. + The Qt Quick application wizard creates a project that contains + the following source files: - \image qml-texteditor5_editmenu.png + \table + \header + \li Source file + \li Purpose + \row + \li alarms.pro + \li The project file + \row + \li main.cpp + \li The main C++ code file for the application. + \row + \li qml.qrc + \li The resource file, which contains the names of the + source files, except main.cpp and the project file. + \endtable - The complete source code is in the \c{examples/quick/tutorials/gettingStartedQml} - directory. If you wish to see how the finalized application looks like, you - can skip to chapter \l {Running the Text Editor}. + The wizard generates the code in the main.cpp file below. + This code block enables High DPI scaling and declares \c app + and \c engine. The engine then loads our main QML file. - The C++ portion of this tutorial assumes that the reader possesses basic knowledge of - Qt's compilation procedures. + \quotefromfile tutorials/alarms/main.cpp + \skipto main + \printuntil } - Tutorial chapters: - \list 1 - \li \l {Defining a Button and a Menu} - \li \l {Implementing a Menu Bar} - \li \l {Building a Text Editor} - \li \l {Decorating the Text Editor} - \li \l {Extending QML using Qt C++} - \endlist + \section1 Additional source files - Information about QML, such as syntax and features, is included in the - \l{The QML Reference}. + \table + \header + \li Source file + \li Purpose + \row + \li \c qtquickcontrols2.conf + \li Selects the \c Material style with the \c Dark theme. + \row + \li \c main.qml + \li The QML code that links AlarmDialog.qml, AlarmModel.qml, + AlarmDelegate.qml and TumblerDelegate.qml + \row + \li \c AlarmDialog.qml + \li Defines the dialog for adding new alarms. + \row + \li \c AlarmDelegate.qml + \li Defines the layout of the main screen of the app. + \row + \li \c AlarmModel.qml + \li Defines the ListModel used for storing the alarms' data. + \row + \li \c TumblerDelegate.qml + \li Defines the graphical layout of the Tumblers + \endtable - \section1 Defining a Button and a Menu - \section2 Basic Component - a Button + \section2 \c qtquickcontrols2.conf - We start our text editor by building a button. Functionally, a button has a mouse - sensitive area and a label. Buttons perform actions when a user presses the button. + The following snippet shows how to set the \c Dark theme in the + \c Material style: - In QML, the basic visual item is the \l Rectangle type. The - \c Rectangle \l{QML Object Types}{QML object type} has - \l{Property Binding}{QML properties} to control its appearance and location. + \quotefile tutorials/alarms/qtquickcontrols2.conf - \code - import QtQuick 2.3 - - Rectangle { - id: simpleButton - color: "grey" - width: 150; height: 75 - - Text { - id: buttonLabel - anchors.centerIn: parent - text: "button label" - } - } - \endcode - - First, the \c {import QtQuick 2.3} statement allows the - \l{Prototyping with qmlscene}{qmlscene} tool to import the QML types we will later use. - This line must exist for every QML file. Notice that the version of Qt modules is - included in the import statement. - - This simple rectangle has a unique identifier, \c simpleButton, which is bound to the - \c id property. The \c Rectangle object's properties are bound to values by listing the - property, followed by a colon, then the value. In the code sample, the color \c grey - is bound to the Rectangle's \c color property. Similarly, we bind the \c width - and \c height of the Rectangle. - - The \l Text type is a non-editable text field. We name this object \c buttonLabel. To set - the string content of the Text field, we bind a value to the \c text property. The label - is contained within the Rectangle and in order to center it in the middle, we assign the - \c anchors of the Text object to its parent, which is called \c simpleButton. Anchors may - bind to other items' anchors, allowing layout assignments simpler. - - We shall save this code as \c SimpleButton.qml. Running \c qmlscene with the file as the - argument will display the grey rectangle with a text label. - - \image qml-texteditor1_simplebutton.png - - To implement the button click functionality, we can use QML's event handling. QML's event - handling is very similar to \l {Signals & Slots}{Qt's signal and slot} mechanism. Signals - are emitted and the connected slot is called. - - \code - Rectangle { - id: simpleButton - ... - - MouseArea { - id: buttonMouseArea - - // Anchor all sides of the mouse area to the rectangle's anchors - anchors.fill: parent - // onClicked handles valid mouse button clicks - onClicked: console.log(buttonLabel.text + " clicked") - } - } - \endcode - - We include a \l MouseArea object in our simpleButton. \c MouseArea objects describe - the interactive area where mouse movements are detected. For our button, we anchor the - whole \c MouseArea to its parent, which is \c simpleButton. The \c anchors.fill syntax is - one way of accessing a specific property called \c fill inside a group of properties - called \c anchors. QML uses \l {Positioning with Anchors}{anchor-based layouts} where - items can anchor to another item, creating robust layouts. - - The \c MouseArea has many signal handlers that are called during mouse movements within - the specified \c MouseArea boundaries. One of them is \c onClicked and it is called - whenever the acceptable mouse button is clicked, the left click being the default. We - can bind actions to the onClicked handler. In our example, \c console.log() outputs text - whenever the mouse area is clicked. The function \c console.log() is a useful tool for - debugging purposes and for outputting text. - - The code in \c SimpleButton.qml is sufficient to display a button on the screen and - output text whenever it is clicked with a mouse. - - \code - Rectangle { - id: button - ... - - property color buttonColor: "lightblue" - property color onHoverColor: "gold" - property color borderColor: "white" - - signal buttonClick() - - onButtonClick: { - console.log(buttonLabel.text + " clicked") - } - - MouseArea{ - id: buttonMouseArea - onClicked: buttonClick() - hoverEnabled: true - onEntered: parent.border.color = onHoverColor - onExited: parent.border.color = borderColor - } - - // Determines the color of the button by using the conditional operator - color: buttonMouseArea.pressed ? Qt.darker(buttonColor, 1.5) : buttonColor - } - \endcode - - A fully functioning button is in \c Button.qml. The code snippets in this article - have some code omitted, denoted by ellipses because they were either introduced - earlier in the previous sections or irrelevant to the current code discussion. - - Custom properties are declared using the \c {property type name} syntax. In the - code, the property \c buttonColor, of type \c color, is declared and bound to - the value \c{"lightblue"}. The \c buttonColor is later used in a conditional - operation to determine the button's fill color. Note that property value - assignment is possible using the \c= equals sign, in addition to value binding - using the \c : colon character. Custom properties allow internal items to be - accessible outside of the Rectangle's scope. There are basic - \l{QML Basic Types}{QML types} such as \c int, \c string, \c real, as well as - a type called \c variant. - - By binding the \c onEntered and \c onExited signal handlers to colors, the - button's border will turn yellow when the mouse hovers above the button and - reverts the color when the mouse exits the mouse area. - - A \c buttonClick() signal is declared in \c Button.qml by placing the \c signal - keyword in front of the signal name. All signals have their handlers automatically - created, their names starting with \c on. As a result, the \c onButtonClick is - \c buttonClick's handler. The \c onButtonClick is then assigned an action to - perform. In our button example, the \c onClicked mouse handler will simply call - \c onButtonClick, which displays a text. The \c onButtonClick enables outside - objects to access the \c {Button}'s mouse area easily. For example, items may - have more than one \c MouseArea declarations and a \c buttonClick signal can - make the distinction between the several \c MouseArea signal handlers better. - - We now have the basic knowledge to implement items in QML that can handle - basic mouse movements. We created a \c Text label inside a \c Rectangle, - customized its properties, and implemented behaviors that respond to mouse - movements. This idea of creating QML objects within objects is repeated - throughout the text editor application. - - This button is not useful unless used as a component to perform an action. - In the next section, we will soon create a menu containing several of these - buttons. - - \image qml-texteditor1_button.png - - \section2 Creating a Menu Page - - Up to this stage, we covered how to create objects and assign behaviors inside - a single QML file. In this section, we will cover how to import QML types and how - to reuse some of the created components to build other components. - - Menus display the contents of a list, each item having the ability to perform an action. - In QML, we can create a menu in several ways. First, we will create a menu containing - buttons which will eventually perform different actions. The menu code is in - \c FileMenu.qml. - - \code - import QtQuick 2.3 // Import the main Qt QML module - import "folderName" // import the contents of a folder - import "script.js" as Script // Import a Javascript file and name it as Script - \endcode - - The syntax shown above shows how to use the \c import keyword. This is required to - use JavaScript files, or QML files that are not within the same directory. Since - \c Button.qml is in the same directory as \c FileMenu.qml, we do not need to import - the \c Button.qml file to use it. We can directly create a \c Button object by declaring - \c Button{}, similar to a \c Rectangle{} declaration. - - \code - In FileMenu.qml: - - Row { - anchors.centerIn: parent - spacing: parent.width / 6 - - Button { - id: loadButton - buttonColor: "lightgrey" - label: "Load" - } - Button { - buttonColor: "grey" - id: saveButton - label: "Save" - } - Button { - id: exitButton - label: "Exit" - buttonColor: "darkgrey" - - onButtonClick: Qt.quit() - } - } - \endcode - - In \c FileMenu.qml, we declare three \c Button objects. They are declared - inside a \l Row type, a positioner that will position its children - along a vertical row. The \c Button declaration resides in Button.qml, - which is the same as the one we used in the previous section. - New property bindings can be declared within the newly created buttons, - effectively overwriting the properties set in \c Button.qml. The button - called \c exitButton will quit and close the window when it is clicked. - Note that the signal handler \c onButtonClick in \c Button.qml will be - called in addition to the \c onButtonClick handler in \c exitButton. - - \image qml-texteditor1_filemenu.png - - The \c Row declaration is declared in a \c Rectangle, creating a rectangle - container for the row of buttons. This additional rectangle creates an indirect - way of organizing the row of buttons inside a menu. - - The declaration of the edit menu is very similar at this stage. The menu has - buttons that have the labels: \c Copy, \c Paste, and \c {Select All}. - - \image qml-texteditor1_editmenu.png - - Armed with our knowledge of importing and customizing previously made - components, we may now combine these menu pages to create a menu bar, - consisting of buttons to select the menu, and look at how we may structure - data using QML. - - \section1 Implementing a Menu Bar - - Our text editor application will need a way to display menus using a menu bar. - The menu bar will switch the different menus and the user can choose which menu - to display. Menu switching implies that the menus need more structure than - merely displaying them in a row. QML uses models and views to structure data - and display the structured data. - - \section2 Using Data Models and Views - - QML has different \l{QML Data Models}{data views} that display - \l{QML Data Models}{data models}. Our menu bar will display the menus in a list, - with a header that displays a row of menu names. The list of menus are declared - inside a \l ObjectModel. The \c ObjectModel type contains items that already are - displayable, such as \c Rectangle objects. Other model types, like the - \l ListModel type, need a delegate to display their data. - - We declare two visual items in the \c menuListModel, the \c FileMenu and the - \c EditMenu. We customize the two menus and display them in a \l ListView. - The \c MenuBar.qml file contains the QML declarations and a simple edit menu is - defined in \c EditMenu.qml. - - \code - ObjectModel { - id: menuListModel - - FileMenu { - width: menuListView.width - height: menuBar.height - color: fileColor - } - - EditMenu { - color: editColor - width: menuListView.width - height: menuBar.height - } - } - \endcode - - The \l ListView type will display a model according to a delegate. The delegate - can display the model items in a \c Row object or in a grid. Our \c menuListModel - already has visible items, therefore, we do not need to declare a delegate. - - \code - ListView { - id: menuListView - - // Anchors are set to react to window anchors - anchors.fill: parent - anchors.bottom: parent.bottom - width: parent.width - height: parent.height - - // The model contains the data - model: menuListModel - - // Control the movement of the menu switching - snapMode: ListView.SnapOneItem - orientation: ListView.Horizontal - boundsBehavior: Flickable.StopAtBounds - flickDeceleration: 5000 - highlightFollowsCurrentItem: true - highlightMoveDuration: 240 - highlightRangeMode: ListView.StrictlyEnforceRange - } - \endcode - - Additionally, \c ListView inherits from \l Flickable, making the list respond - to mouse drags and other gestures. The last portion of the code above sets - \c Flickable properties to create the desired flicking movement to our view. - In particular, the property \c highlightMoveDuration changes the duration of - the flick transition. A higher \c highlightMoveDuration value results in - slower menu switching. - - The \c ListView maintains the model items through an \c index and each visual - item in the model is accessible through the \c index, in the order of the - declaration. Changing the \c currentIndex effectively changes the highlighted - item in the \c ListView. The header of our menu bar exemplifies this effect. - There are two buttons in a row, both changing the current menu when clicked. - The \c fileButton changes the current menu to the file menu when clicked, - the \c index being \c 0 because \c FileMenu is declared first in the - \c menuListModel. Similarly, the \c editButton will change the current - menu to the \c EditMenu when clicked. - - The \c labelList rectangle has \c z value of \c 1, denoting that it is displayed - at the front of the menu bar. Items with higher \c z values are displayed in front - of items with lower \c z values. The default \c z value is \c 0. - - \code - Rectangle { - id: labelList - ... - z: 1 - - Row { - anchors.centerIn: parent - spacing: 40 - - Button { - label: "File" - id: fileButton - ... - onButtonClick: menuListView.currentIndex = 0 - } - - Button { - id: editButton - label: "Edit" - ... - onButtonClick: menuListView.currentIndex = 1 - } - } - } - \endcode - - The menu bar we just created can be flicked to access the menus or by clicking - on the menu names at the top. Switching menu screens feel intuitive and responsive. - - \image qml-texteditor2_menubar.png - - \section1 Building a Text Editor - - \section2 Declaring a TextArea - - Our text editor is not a text editor if it didn't contain an editable text area. - QML's \l TextEdit type allows the declaration of a multi-line editable text area. - \c TextEdit is different from the \l Text type, which doesn't allow the user to - directly edit the text. - - \code - TextEdit { - id: textEditor - anchors.fill: parent - width: parent.width - height: parent.height - color: "midnightblue" - focus: true - - wrapMode: TextEdit.Wrap - - onCursorRectangleChanged: flickArea.ensureVisible(cursorRectangle) - } - \endcode - - The editor has its font \c color property set and \c wrapMode set to wrap the text. - The \c TextEdit area is inside a flickable item that will scroll the text if the - text cursor is outside the visible area. The function \c ensureVisible() will - check if the cursor rectangle is outside the visible boundaries and move the - text area accordingly. QML uses Javascript syntax for its scripts, and as previously - mentioned, Javascript files can be imported and used within a QML file. - - \code - function ensureVisible(r) { - if (contentX >= r.x) - contentX = r.x; - else if (contentX + width <= r.x + r.width) - contentX = r.x + r.width - width; - if (contentY >= r.y) - contentY = r.y; - else if (contentY + height <= r.y + r.height) - contentY = r.y + r.height - height; - } - \endcode - - \section2 Combining Components for the Text Editor - - We are now ready to create the layout of our text editor using QML. The text - editor has two components, the menu bar we created and the text area. QML allows - us to reuse components, therefore making our code simpler, by importing components - and customizing when necessary. Our text editor splits the window into two; - one-third of the screen is dedicated to the menu bar and two-thirds of the screen - displays the text area. The menu bar is displayed in front of any other objects. - - \code - Rectangle { - id: screen - width: 1000 - height: 1000 - - // The screen is partitioned into the MenuBar and TextArea. - // One-third of the screen is assigned to the MenuBar - property int partition: height / 3 - - MenuBar { - id: menuBar - height: partition - width: parent.width - z: 1 - } - - TextArea { - id: textArea - anchors.bottom: parent.bottom - y: partition - color: "white" - width: parent.width - height: partition * 2 - } - } - \endcode - - By importing reusable components, our \c TextEditor code looks much simpler. - We can then customize the main application, without worrying about properties - that already have defined behaviors. Using this approach, application layouts - and UI components can be created easily. - - \image qml-texteditor3_texteditor.png - - \section1 Decorating the Text Editor - \section2 Implementing a Drawer Interface - - Our text editor looks simple and we need to decorate it. Using QML, we can declare - transitions and animate our text editor. Our menu bar is occupying one-third of the - screen and it would be nice to have it only appear when we want it. - - We can add a drawer interface, that will contract or expand the menu bar when clicked. - In our implementation, we have a thin rectangle that responds to mouse clicks. The - \c drawer, as well as the application, has two sates: the "drawer is open" state and - the "drawer is closed" state. The \c drawer item is a strip of rectangle with a small - height. There is a nested \l Image object declaring that an arrow icon will - be centered inside the drawer. The drawer assigns a state to the whole application, - with the identifier \c screen, whenever a user clicks the mouse area. - - \code - Rectangle { - id: drawer - height: 15 - - Image { - id: arrowIcon - source: "images/arrow.png" - anchors.horizontalCenter: parent.horizontalCenter - } - - MouseArea { - id: drawerMouseArea - anchors.fill: parent - - onClicked: { - if (screen.state == "DRAWER_CLOSED") - screen.state = "DRAWER_OPEN" - else if (screen.state == "DRAWER_OPEN") - screen.state = "DRAWER_CLOSED" - } - ... - } - } - \endcode - - A state is simply a collection of configurations and it is declared with the - \l State type. A list of states can be listed and bound to the \c states property. - In our application, the two states are called \c DRAWER_CLOSED and \c DRAWER_OPEN. - Item configurations are declared in \l PropertyChanges objects. In the - \c DRAWER_OPEN state, there are four items that will receive property changes. - The first target, \c menuBar, will change its \c y property to \c 0. Similarly, - the \c textArea will lower to a new position when the state is \c DRAWER_OPEN. - The \c textArea, the \c drawer, and the drawer's icon will undergo property - changes to meet the current state. - - \code - states:[ - State { - name: "DRAWER_OPEN" - PropertyChanges { target: menuBar; y: 0 } - PropertyChanges { target: textArea; y: partition + drawer.height } - PropertyChanges { target: drawer; y: partition } - PropertyChanges { target: arrowIcon; rotation: 180 } - }, - State { - name: "DRAWER_CLOSED" - PropertyChanges { target: menuBar; y: -height; } - PropertyChanges { target: textArea; y: drawer.height; height: screen.height - drawer.height } - PropertyChanges { target: drawer; y: 0 } - PropertyChanges { target: arrowIcon; rotation: 0 } - } - ] - \endcode - - State changes are abrupt and needs smoother transitions. Transitions between states - are defined using the \l Transition type, which can then bind to the item's - \c transitions property. Our text editor has a state transition whenever the state - changes to either \c DRAWER_OPEN or \c DRAWER_CLOSED. Importantly, the transition - needs a \c from and a \c to state but for our transitions, we can use the wild card - \c * symbol to denote that the transition applies to all state changes. - - During transitions, we can assign animations to the property changes. Our \c menuBar - switches position from \c {y: 0} to \c {y: -partition} and we can animate this - transition using the \l NumberAnimation type. We declare that the targets' - properties will animate for a certain duration of time and using a certain easing - curve. An easing curve controls the animation rates and interpolation behavior - during state transitions. The easing curve we chose is - \l{PropertyAnimation::easing.type}{\c Easing.OutExpo}, which slows the movement near - the end of the animation. For more information, see QML's - \l {Animation and Transitions in Qt Quick}{animation} article. - - \code - transitions: [ - Transition { - to: "*" - NumberAnimation { target: textArea; properties: "y, height"; duration: 100; easing.type:Easing.OutExpo } - NumberAnimation { target: menuBar; properties: "y"; duration: 100; easing.type: Easing.OutExpo } - NumberAnimation { target: drawer; properties: "y"; duration: 100; easing.type: Easing.OutExpo } - } - ] - \endcode - - Another way of animating property changes is by declaring a \l Behavior - type. A transition only works during state changes and \c Behavior can set an - animation for a general property change. In the text editor, the arrow has a - \c NumberAnimation animating its \c rotation property whenever the property changes. - - In \c {TextEditor.qml}: - - \code - Behavior { - NumberAnimation { property: "rotation"; easing.type: Easing.OutExpo } - } - \endcode - - Going back to our components with knowledge of states and animations, we can improve - the appearances of the components. In \c Button.qml, we can add \c color and \c scale - property changes when the button is clicked. Color types are animated using - \l ColorAnimation and numbers are animated using \l NumberAnimation. The - \c {on propertyName} syntax displayed below is helpful when targeting a single property. - - In \c {Button.qml}: - \code - ... - - color: buttonMouseArea.pressed ? Qt.darker(buttonColor, 1.5) : buttonColor - Behavior on color { ColorAnimation{ duration: 55 } } - - scale: buttonMouseArea.pressed ? 1.1 : 1.0 - Behavior on scale { NumberAnimation{ duration: 55 } } - \endcode - - Additionally, we can enhance the appearances of our QML components by adding color - effects such as gradients and opacity effects. Declaring a \l Gradient object will - override the \c color property. You may declare a color in the gradient using the - \l GradientStop type. The gradient is positioned using a scale, between \c 0.0 and - \c 1.0. - - In \c {MenuBar.qml}: - - \code - gradient: Gradient { - GradientStop { position: 0.0; color: "#8C8F8C" } - GradientStop { position: 0.17; color: "#6A6D6A" } - GradientStop { position: 0.98; color: "#3F3F3F" } - GradientStop { position: 1.0; color: "#0e1B20" } - } - \endcode - - This gradient is used by the menu bar to display a gradient simulating depth. - The first color starts at \c 0.0 and the last color is at \c 1.0. - - \section3 Where to Go from Here + \section2 \c main.qml - We are finished building the user interface of a very simple text editor. - Going forward, the user interface is complete, and we can implement the - application logic using regular Qt and C++. QML works nicely as a prototyping - tool, separating the application logic away from the UI design. + \c mainWindow, an ApplicationWindow QML type, is the root item in + this app. - \image qml-texteditor4_texteditor.png + \quotefromfile tutorials/alarms/main.qml + \skipto ApplicationWindow + \printuntil visible - \section2 Extending QML using Qt C++ + The ListView \c alarmListView combines the data from \c alarmModel + with the layout defined in \c alarmDelegate. - Now that we have our text editor layout, we may now implement the text editor - functionalities in C++. Using QML with C++ enables us to create our application - logic using Qt. We can create a QML context in a C++ application using - \l {Integrating QML and C++}{Qt's Quick classes} and display the QML - types using a QQuickView. Alternatively, we can export our C++ code into - an extension plugin, and make it accessible to QML as a new - \l {Identified Modules}{identified module}. - When launching QML files with \l {Prototyping with qmlscene}{qmlscene}, - we only need to ensure our module is found under one of the - \l {QML Import Path}{import paths} the QML engine searches for modules - to import. For our application we shall the latter approach. This way, we can - load the QML file directly with \c qmlscene instead of running an executable. + \quotefromfile tutorials/alarms/main.qml + \skipuntil visible + \printto RoundButton - \section3 Exposing C++ Classes to QML + New alarms can be added by clicking RoundButton \c addAlarmButton. + Clicking it opens a \l {Dialog: QtQuickControls2}{dialog} screen \c alarmDialog. - We will be implementing file loading and saving using Qt and C++. C++ classes - and functions can be used in QML by registering them. They also needs to be - compiled as a Qt plugin and then exposed as a QML module. + \printuntil alarmDialog.open + \printuntil alarmListView.model + \printline } - For our application, we need to create the following items: - \list 1 - \li \c Directory class that will handle directory related operations - \li \c File class which is a QObject, simulating the list of files in a directory - \li A plugin class that will register the classes to the QML context - \li Qt project file that will compile the plugin - \li A \l {Module Definition qmldir Files}{module definition qmldir file} that - defines the identifier (import URI) and content (in this case, our plugin) - to be made available by the QML module - \endlist - - \note Since Qt 5.1, \l{Qt Quick Dialogs} module provides a file dialog component - that you can use for choosing files from the local file system. For illustrative - purposes, we write our own in this tutorial. - - \section3 Building a Qt Plugin - - To build a plugin, we need to set the following in a Qt project file. First, - the necessary sources, headers, and Qt modules need to be added into our - project file. All the C++ code and project files are in the \c filedialog - directory. - - In \c {filedialog.pro}: - - \code - TEMPLATE = lib - CONFIG += qt plugin - QT += qml - - DESTDIR += ../imports/FileDialog - OBJECTS_DIR = tmp - MOC_DIR = tmp - - TARGET = filedialogplugin - - HEADERS += \ - directory.h \ - file.h \ - dialogPlugin.h - - SOURCES += \ - directory.cpp \ - file.cpp \ - dialogPlugin.cpp - \endcode + \section2 \c AlarmDialog.qml - In particular, we link the project with the \c qml module and configure it as a - \c plugin, using a \c lib template. We shall put the compiled plugin into the - parent's \c {imports/FileDialog} directory. + This dialog screen has a RowLayout with a \l {Tumbler} each for hours + and minutes, and another RowLayout with a Tumbler each for day, month, + and year. - \section3 Registering a Class into QML + \quotefromfile tutorials/alarms/AlarmDialog.qml + \skipto contentItem + \printuntil "model: years" + \printuntil } - In \c {dialogPlugin.h}: + If you click on \b OK in the dialog, the entered data will be + added to \c alarmModel: - \code - #include + \quotefromfile tutorials/alarms/AlarmDialog.qml + \skipto onAccepted + \printuntil onRejected - class DialogPlugin : public QQmlExtensionPlugin - { - Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.QmlExtensionPlugin.FileDialog") + \section2 \c AlarmDelegate.qml - public: - // registerTypes is inherited from QQmlExtensionPlugin - void registerTypes(const char *uri); - }; + Each alarm in the main screen is an ItemDelegate. The ItemDelegate + \c root contains all fields on the main screen and the detail + screen. The detail screen's fields are only visible after an alarm + has been clicked on, i.e. when \c root.checked is \c true. - \endcode + \quotefromfile tutorials/alarms/AlarmDelegate.qml + \skipto ItemDelegate + \printuntil /^\}/ - We need to export the plugin using the \l {How To Create Qt Plugins}{Q_PLUGIN_METADATA} macro. - Note that in our \c dialogPlugin.h file, we have the \l Q_OBJECT - macro at the top of our class. As well, we need to run \c qmake on the project - file to generate the necessary meta-object code. + \section2 \c AlarmModel.qml - Our plugin class, \c {DialogPlugin}, is a subclass of \l{QQmlExtensionPlugin}. - We need to implement the inherited function, - \l {QQmlExtensionPlugin::registerTypes()}{registerTypes()}. + This QML file contains the definition of \c alarmModel, the ListModel + that manages the alarm data. - In \c {DialogPlugin.cpp}: + It creates five \l {ListElement}{ListElements} with example alarms. - \code - #include "dialogPlugin.h" - #include "directory.h" - #include "file.h" - #include - - void DialogPlugin::registerTypes(const char *uri) - { - // Register the class Directory into QML as a "Directory" type version 1.0 - // @uri FileDialog - qmlRegisterType(uri, 1, 0, "Directory"); - qmlRegisterType(uri, 1, 0, "File"); - } - \endcode + \quotefromfile tutorials/alarms/AlarmModel.qml + \skipto import + \printuntil /^\}/ - The \c registerTypes() function registers our File and Directory classes into - QML. This function needs the class name for its template, a major version number, - a minor version number, and a name for our classes. - A \c {// @uri } comment allows Qt Creator to be aware of the - registered types when editing QML files that import this module. + \section2 TumblerDelegate.qml - \section3 Creating QML Properties in a C++ Class + TumblerDelegate defines the graphical properties of the Tumblers. - We can create QML types and properties using C++ and - \l {The Meta-Object System}{Qt's Meta-Object System}. We can implement - properties using slots and signals, making Qt aware of these properties. - These properties can then be used in QML. + \quotefromfile tutorials/alarms/TumblerDelegate.qml + \skipto import + \printuntil /^\}/ - For the text editor, we need to be able to load and save files. Typically, - these features are contained in a file dialog. Fortunately, we can use - \l QDir, \l QFile, and \l QTextStream to implement directory reading and - input/output streams. + \section1 Entering new alarms - \code - class Directory : public QObject { - Q_OBJECT - - Q_PROPERTY (int filesCount READ filesCount CONSTANT) - Q_PROPERTY (QString filename READ filename WRITE setFilename NOTIFY filenameChanged) - Q_PROPERTY (QString fileContent READ fileContent WRITE setFileContent NOTIFY fileContentChanged) - Q_PROPERTY (QQmlListProperty files READ files CONSTANT) - ... - \endcode + At the bottom of the startup screen, you can see a Button for adding + alarms. Click it to open the \b {Add new alarm} dialog. - The \c Directory class uses Qt's Meta-Object System to register properties it - needs to accomplish file handling. The \c Directory class is exported as a plugin - and is useable in QML as the \c Directory type. Each of the listed properties - using the \l Q_PROPERTY() macro is a QML property. + \quotefromfile tutorials/alarms/main.qml + \skipto RoundButton + \printto AlarmDialog - The \l {Q_PROPERTY()}{Q_PROPERTY} declares a property as well as its read and - write functions into Qt's Meta-Object System. For example, the \c filename - property, of type \l QString, is readable using the \c filename() - function and writable using the function \c setFilename(). Additionally, there - is a signal associated to the filename property called \c {filenameChanged()}, - which is emitted whenever the property changes. The read and write functions - are declared as \c public in the header file. + The dialog for new alarms: - Similarly, we have the other properties declared according to their uses. The - \c filesCount property indicates the number of files in a directory. The filename - property is set to the currently selected file's name and the loaded/saved file - content is stored in \c fileContent property. + \image addalarms.png "Add alarms" - \code - Q_PROPERTY(QQmlListProperty files READ files CONSTANT) - \endcode + All fields are entered using \l {Tumbler} QML types. If you press \c OK, + the values selected in the Tumblers are written to \c alarmModel. - The \c files list property is a list of all the filtered files in a directory. - The \c Directory class is implemented to filter out invalid text files; only - files with a \c .txt extension are valid. Further, \l{QList}s can be - used in QML files by declaring them as a QQmlListProperty in C++. - The templated object needs to inherit from a QObject, therefore, - the \c File class must also inherit from QObject. In the \c Directory class, - the list of \c File objects is stored in a QList called \c m_fileList. + \quotefromfile tutorials/alarms/AlarmDialog.qml + \skipto contentItem + \printuntil " }" - \code - class File : public QObject{ + \section1 Editing alarms - Q_OBJECT - Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + If you click on a particular alarm, you can edit it in the detail + screen. - ... - }; - \endcode + \image detailscreen.png - The properties can then be used in QML as part of the \c Directory object's - properties. Note that we do not have to create an identifier \c id property - in our C++ code. + Clicking on an alarm sets \c root.checked to \c true, which makes + visible the fields of the detail screen. \code - Directory { - id: directory - - filesCount - filename - fileContent - files - - files[0].name - } + visible: root.checked \endcode - Because QML uses Javascript's syntax and structure, we can iterate through - the list of files and retrieve its properties. To retrieve the first file's - name property, we can call \c {files[0].name}. + If you want the alarm to trigger also on other days, check \c alarmRepeat. + The Repeater will display a checkable RoundButton for each day of the week. - Regular C++ functions are also accessible from QML. The file loading and saving - functions are implemented in C++ and declared using the \l Q_INVOKABLE macro. - Alternatively, we can declare the functions as a \c slot and the functions will - be accessible from QML. + \quotefromfile tutorials/alarms/AlarmDelegate.qml + \skipto Flow + \printto TextField - In \c {directory.h}: + If you modify the description of the alarm, it will be reflected in + the main screen afterwards. - \code - Q_INVOKABLE void saveFile(); - Q_INVOKABLE void loadFile(); - \endcode + \printto Button - The \c Directory class also has to notify other objects whenever the directory - contents change. This feature is performed using a \c signal. As previously - mentioned, QML signals have a corresponding handler with their names prepended - with \c on. The signal is called \c directoryChanged and it is emitted whenever - there is a directory refresh. The refresh simply reloads the directory contents - and updates the list of valid files in the directory. QML items can then be - notified by attaching an action to the \c onDirectoryChanged signal handler. - - The \c list properties need to be explored further. This is because list - properties use callbacks to access and modify the list contents. The list - property is of type \c QQmlListProperty. Whenever the list - is accessed, the accessor function needs to return a - \c QQmlListProperty. The template type, \c File, needs to be a - \c QObject derivative. Further, to create the - \c QQmlListProperty, the list's accessor - and modifiers need to be passed to the constructor as function pointers. The list, - a \c QList in our case, also needs to be a list of \c File pointers. - - The constructor of \l QQmlListProperty is declared - as follows: - \code - QQmlListProperty (QObject *object, void *data, AppendFunction append, - CountFunction count = 0, AtFunction at = 0, ClearFunction clear = 0); - \endcode + \section1 Deleting alarms - It takes pointers to functions that will append the list, count - the list, retrieve the item using an index, and empty the list. Only the \c append - function is mandatory. Note that the function pointers must match the definition - of \l {QQmlListProperty::AppendFunction}{AppendFunction}, - \l {QQmlListProperty::CountFunction}{CountFunction}, - \l {QQmlListProperty::AtFunction}{AtFunction}, or - \l {QQmlListProperty::ClearFunction}{ClearFunction}. + The detail screen (see above) has a Button for deleting alarms. + When \c onClicked is emitted, the current ListElement is deleted + from \c alarmModel. - The \c Directory class constructs a QQmlListProperty instance like this: + \printuntil alarmModel.remove + \printuntil } - \code - QQmlListProperty(this, &m_fileList, &appendFiles, &filesSize, &fileAt, &clearFilesPtr); - \endcode - - Where the parameters are pointers to following functions: - - \code - void appendFiles(QQmlListProperty *property, File *file); - File* fileAt(QQmlListProperty *property, int index); - int filesSize(QQmlListProperty *property); - void clearFilesPtr(QQmlListProperty *property); - \endcode + \section2 Summary - To simplify our file dialog, the \c Directory class filters out invalid text - files, which are files that do not have a \c .txt extension. If a file name - doesn't have the \c .txt extension, then it won't be seen in our file dialog. - Also, the implementation makes sure that saved files have a \c .txt extension in - the file name. \c Directory uses \l {QTextStream} to read the file and to output - the file contents to a file. + The app has no code for adding sound or vibration to the alarm, nor does + it store the alarms in any format or database. Maybe it could be an + interesting coding project to add those features. Adding sound to this + program can be realized with \l{Qt Multimedia QML Types}. Storing the data + could be done quickly and easily in \l{JSON Support in Qt}{JSON format}. - With our \c Directory object, we can retrieve the files as a list, know how many - text files is in the application directory, get the file's name and content as a - string, and be notified whenever there are changes in the directory contents. - - To build the plugin, run \c qmake on the \c filedialog.pro project file, then run - \c make to build and transfer the plugin to the \c plugins directory. - - - \section3 Importing a Plugin in QML - - The \c qmlscene tool imports files that are in the same directory as the - application. We can also create a \c qmldir file containing the locations of - content we wish to import. In this case, there is only the plugin, but other - resources (QML types, JavaScript files) can be defined in a \c qmldir as well. - - Contents of the \c qmldir file: - \code - module FileDialog - plugin filedialogplugin - \endcode - - The module we just created is called \c FileDialog, and it makes available a plugin - called \c filedialogplugin that matches the \c TARGET field in the project file. - Because we did not specify a path for the plugin, the QML engine expects to find it - in the same directory as the \c qmldir file. - - The QML types that are registered by our plugin can now be imported in QML: - - \code - import FileDialog 1.0 - - Directory { - id: directory - } - ... - \endcode - - - \section3 Integrating a File Dialog into the File Menu - - Our \c FileMenu needs to display the \c FileDialog object, containing a list of - the text files in a directory thus allowing the user to select the file by - clicking on the list. We also need to assign the save, load, and new buttons - to their respective actions. The FileMenu contains an editable text input to - allow the user to type a file name using the keyboard. - - The \c Directory object is used in the \c FileMenu.qml file and it notifies the - \c FileDialog object that the directory refreshed its contents. This notification - is performed in the signal handler, \c onDirectoryChanged. - - In \c {FileMenu.qml}: - - \code - Directory { - id: directory - filename: textInput.text - onDirectoryChanged: fileDialog.notifyRefresh() - } - \endcode - - Keeping with the simplicity of our application, the file dialog will always be - visible and will not display invalid text files, which do not have a \c .txt - extension to their filenames. - - In \c {FileDialog.qml}: - - \code - signal notifyRefresh() - onNotifyRefresh: dirView.model = directory.files - \endcode - - The \c FileDialog object will display the contents of a directory by reading its - list property called \c files. The files are used as the model of a - \l {GridView} object, which displays data items in a grid according - to a delegate. The delegate handles the appearance of the model and our file - dialog will simply create a grid with text centered in the middle. Clicking on - the file name will result in the appearance of a rectangle to highlight the file - name. The \c FileDialog is notified whenever the \c notifyRefresh signal is emitted, - reloading the files in the directory. - - In \c {FileMenu.qml}: - - \code - Button { - id: newButton - label: "New" - onButtonClick: { - textArea.textContent = "" - } - } - Button { - id: loadButton - label: "Load" - onButtonClick: { - directory.filename = textInput.text - directory.loadFile() - textArea.textContent = directory.fileContent - } - } - Button { - id: saveButton - label: "Save" - onButtonClick: { - directory.fileContent = textArea.textContent - directory.filename = textInput.text - directory.saveFile() - } - } - Button { - id: exitButton - label: "Exit" - onButtonClick: { - Qt.quit() - } - } - \endcode - - Our \c FileMenu can now connect to their respective actions. The \c saveButton - will transfer the text from the \c TextEdit onto the directory's \c fileContent - property, then copy its file name from the editable text input. Finally, the button - calls the \c saveFile() function, saving the file. The \c loadButton has a similar - execution. Also, the \c New action will empty the contents of the \c TextEdit. - - Further, the \c EditMenu buttons are connected to the \c TextEdit functions to copy, - paste, and select all the text in the text editor. - - \image qml-texteditor5_filemenu.png - - \section2 Final Text Editor Application - - \image qml-texteditor5_newfile.png - - The application can function as a simple text editor, able to accept text - and save it into a file. It can also load a file and perform text manipulation. - - \section1 Running the Text Editor - - We need to build the file dialog C++ plugin before the text editor can run. - To build it, enter the \c filedialog directory, then run \c qmake and compile - using \c make or \c nmake, depending on your platform. - - Run the text editor with \l{Prototyping with qmlscene}{qmlscene}, passing the - imports directory as a parameter so that the QML engine knows where to look for - the module that imports our file dialog plugin: - - \code - qmlscene -I ./imports texteditor.qml - \endcode + \sa {Qt Multimedia QML Types}, {JSON Support in Qt} - The complete source code is in \c{examples/quick/tutorials/gettingStartedQml} directory. -*/ diff --git a/doc/src/images/addalarms.png b/doc/src/images/addalarms.png new file mode 100644 index 00000000..2874d2e6 Binary files /dev/null and b/doc/src/images/addalarms.png differ diff --git a/doc/src/images/alarms2.png b/doc/src/images/alarms2.png new file mode 100644 index 00000000..dbcb852c Binary files /dev/null and b/doc/src/images/alarms2.png differ diff --git a/doc/src/images/alarms3.png b/doc/src/images/alarms3.png new file mode 100644 index 00000000..48abec6a Binary files /dev/null and b/doc/src/images/alarms3.png differ diff --git a/doc/src/images/detailscreen.png b/doc/src/images/detailscreen.png new file mode 100644 index 00000000..bc0f0afb Binary files /dev/null and b/doc/src/images/detailscreen.png differ diff --git a/doc/src/images/mainscreen.png b/doc/src/images/mainscreen.png new file mode 100644 index 00000000..e0c5e979 Binary files /dev/null and b/doc/src/images/mainscreen.png differ diff --git a/examples/tutorials/alarms/AlarmDelegate.qml b/examples/tutorials/alarms/AlarmDelegate.qml new file mode 100644 index 00000000..97ffc867 --- /dev/null +++ b/examples/tutorials/alarms/AlarmDelegate.qml @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.4 +import QtQuick.Layouts 1.11 +import QtQuick.Window 2.11 + +ItemDelegate { + id: root + width: parent.width + checkable: true + + onClicked: ListView.view.currentIndex = index + + contentItem: ColumnLayout { + spacing: 0 + + RowLayout { + ColumnLayout { + id: dateColumn + + readonly property date alarmDate: new Date( + model.year, model.month - 1, model.day, model.hour, model.minute) + + Label { + id: timeLabel + font.pixelSize: Qt.application.font.pixelSize * 2 + text: dateColumn.alarmDate.toLocaleTimeString(window.locale, Locale.ShortFormat) + } + RowLayout { + Label { + id: dateLabel + text: dateColumn.alarmDate.toLocaleDateString(window.locale, Locale.ShortFormat) + } + Label { + id: alarmAbout + text: "βΈ± " + model.label + visible: model.label.length > 0 && !root.checked + } + } + } + Item { + Layout.fillWidth: true + } + Switch { + checked: model.activated + Layout.alignment: Qt.AlignTop + onClicked: model.activated = checked + } + } + CheckBox { + id: alarmRepeat + text: qsTr("Repeat") + checked: model.repeat + visible: root.checked + onToggled: model.repeat = checked + } + Flow { + visible: root.checked && model.repeat + Layout.fillWidth: true + + Repeater { + id: dayRepeater + model: daysToRepeat + delegate: RoundButton { + text: Qt.locale().dayName(model.dayOfWeek, Locale.NarrowFormat) + flat: true + checked: model.repeat + checkable: true + Material.background: checked ? Material.accent : "transparent" + onToggled: model.repeat = checked + } + } + } + + TextField { + id: alarmDescriptionTextField + placeholderText: qsTr("Enter description here") + cursorVisible: true + visible: root.checked + text: model.label + onTextEdited: model.label = text + } + Button { + id: deleteAlarmButton + text: qsTr("Delete") + width: 40 + height: 40 + visible: root.checked + onClicked: alarmModel.remove(alarmListView.currentIndex, 1) + } + } +} diff --git a/examples/tutorials/alarms/AlarmDialog.qml b/examples/tutorials/alarms/AlarmDialog.qml new file mode 100644 index 00000000..10e5a264 --- /dev/null +++ b/examples/tutorials/alarms/AlarmDialog.qml @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 +import QtQuick.Controls 2.4 +import QtQuick.Layouts 1.11 +import QtQuick.Window 2.11 + +Dialog { + id: alarmDialog + title: "Add new alarm" + modal: true + standardButtons: DialogButtonBox.Ok | DialogButtonBox.Cancel + + property AlarmModel alarmModel + + function formatNumber(number) { + return number < 10 && number >= 0 ? "0" + number : number.toString() + } + + onAccepted: { + alarmModel.append({ + "hour": hoursTumbler.currentIndex, + "minute": minutesTumbler.currentIndex, + "day": dayTumbler.currentIndex + 1, + "month": monthTumbler.currentIndex + 1, + "year": yearTumbler.years[yearTumbler.currentIndex], + "activated": true, + "label": "", + "repeat": false, + "daysToRepeat": [ + { "dayOfWeek": 0, "repeat": false }, + { "dayOfWeek": 1, "repeat": false }, + { "dayOfWeek": 2, "repeat": false }, + { "dayOfWeek": 3, "repeat": false }, + { "dayOfWeek": 4, "repeat": false }, + { "dayOfWeek": 5, "repeat": false }, + { "dayOfWeek": 6, "repeat": false } + ], + }) + } + onRejected: alarmDialog.close() + + contentItem: RowLayout { + RowLayout { + id: rowTumbler + + Tumbler { + id: hoursTumbler + model: 24 + delegate: TumblerDelegate { + text: formatNumber(modelData) + } + } + Tumbler { + id: minutesTumbler + model: 60 + delegate: TumblerDelegate { + text: formatNumber(modelData) + } + } + } + + RowLayout { + id: datePicker + + Layout.leftMargin: 20 + + property alias dayTumbler: dayTumbler + property alias monthTumbler: monthTumbler + property alias yearTumbler: yearTumbler + + readonly property var days: [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] + + Tumbler { + id: dayTumbler + + function updateModel() { + // Populate the model with days of the month. For example: [0, ..., 30] + var previousIndex = dayTumbler.currentIndex + var array = [] + var newDays = datePicker.days[monthTumbler.currentIndex] + for (var i = 1; i <= newDays; ++i) + array.push(i) + dayTumbler.model = array + dayTumbler.currentIndex = Math.min(newDays - 1, previousIndex) + } + + Component.onCompleted: updateModel() + + delegate: TumblerDelegate { + text: formatNumber(modelData) + } + } + Tumbler { + id: monthTumbler + + onCurrentIndexChanged: dayTumbler.updateModel() + + model: 12 + delegate: TumblerDelegate { + text: window.locale.standaloneMonthName(modelData, Locale.ShortFormat) + } + } + Tumbler { + id: yearTumbler + + // This array is populated with the next three years. For example: [2018, 2019, 2020] + readonly property var years: (function() { + var currentYear = new Date().getFullYear() + return [0, 1, 2].map(function(value) { return value + currentYear; }) + })() + + model: years + delegate: TumblerDelegate { + text: formatNumber(modelData) + } + } + } + } +} diff --git a/examples/tutorials/alarms/AlarmModel.qml b/examples/tutorials/alarms/AlarmModel.qml new file mode 100644 index 00000000..6afa5db7 --- /dev/null +++ b/examples/tutorials/alarms/AlarmModel.qml @@ -0,0 +1,152 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 + +// Populate the model with some sample data. +ListModel { + id: alarmModel + + ListElement { + hour: 6 + minute: 0 + day: 2 + month: 8 + year: 2018 + activated: true + label: "Wake up" + repeat: true + daysToRepeat: [ + ListElement { dayOfWeek: 0; repeat: false }, + ListElement { dayOfWeek: 1; repeat: false }, + ListElement { dayOfWeek: 2; repeat: false }, + ListElement { dayOfWeek: 3; repeat: false }, + ListElement { dayOfWeek: 4; repeat: false }, + ListElement { dayOfWeek: 5; repeat: false }, + ListElement { dayOfWeek: 6; repeat: false } + ] + } + ListElement { + hour: 6 + minute: 0 + day: 3 + month: 8 + year: 2018 + activated: true + label: "Wake up" + repeat: true + daysToRepeat: [ + ListElement { dayOfWeek: 0; repeat: true }, + ListElement { dayOfWeek: 1; repeat: true }, + ListElement { dayOfWeek: 2; repeat: true }, + ListElement { dayOfWeek: 3; repeat: true }, + ListElement { dayOfWeek: 4; repeat: true }, + ListElement { dayOfWeek: 5; repeat: false }, + ListElement { dayOfWeek: 6; repeat: false } + ] + } + ListElement { + hour: 7 + minute: 0 + day: 3 + month: 8 + year: 2018 + activated: false + label: "Exercise" + repeat: true + daysToRepeat: [ + ListElement { dayOfWeek: 0; repeat: true }, + ListElement { dayOfWeek: 1; repeat: true }, + ListElement { dayOfWeek: 2; repeat: true }, + ListElement { dayOfWeek: 3; repeat: true }, + ListElement { dayOfWeek: 4; repeat: true }, + ListElement { dayOfWeek: 5; repeat: true }, + ListElement { dayOfWeek: 6; repeat: true } + ] + } + ListElement { + hour: 5 + minute: 15 + day: 1 + month: 9 + year: 2018 + activated: true + label: "" + repeat: false + daysToRepeat: [ + ListElement { dayOfWeek: 0; repeat: false }, + ListElement { dayOfWeek: 1; repeat: false }, + ListElement { dayOfWeek: 2; repeat: false }, + ListElement { dayOfWeek: 3; repeat: false }, + ListElement { dayOfWeek: 4; repeat: false }, + ListElement { dayOfWeek: 5; repeat: false }, + ListElement { dayOfWeek: 6; repeat: false } + ] + } + ListElement { + hour: 5 + minute: 45 + day: 3 + month: 9 + year: 2018 + activated: false + label: "" + repeat: false + daysToRepeat: [ + ListElement { dayOfWeek: 0; repeat: false }, + ListElement { dayOfWeek: 1; repeat: false }, + ListElement { dayOfWeek: 2; repeat: false }, + ListElement { dayOfWeek: 3; repeat: false }, + ListElement { dayOfWeek: 4; repeat: false }, + ListElement { dayOfWeek: 5; repeat: false }, + ListElement { dayOfWeek: 6; repeat: false } + ] + } +} diff --git a/examples/tutorials/alarms/TumblerDelegate.qml b/examples/tutorials/alarms/TumblerDelegate.qml new file mode 100644 index 00000000..88a35a5b --- /dev/null +++ b/examples/tutorials/alarms/TumblerDelegate.qml @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.4 + +Text { + text: modelData + color: Tumbler.tumbler.Material.foreground + font: Tumbler.tumbler.font + opacity: 1.0 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2) + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter +} diff --git a/examples/tutorials/alarms/alarms.pro b/examples/tutorials/alarms/alarms.pro new file mode 100644 index 00000000..6c54c7f8 --- /dev/null +++ b/examples/tutorials/alarms/alarms.pro @@ -0,0 +1,29 @@ +QT += qml quick + +CONFIG += c++11 + +SOURCES += main.cpp + +RESOURCES += qml.qrc + +# Additional import path used to resolve QML modules in Qt Creator's code model +QML_IMPORT_PATH = $$PWD/imports + +# Additional import path used to resolve QML modules just for Qt Quick Designer +QML_DESIGNER_IMPORT_PATH = + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS +TARGET = Alarms +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/examples/tutorials/alarms/main.cpp b/examples/tutorials/alarms/main.cpp new file mode 100644 index 00000000..3e1bdd84 --- /dev/null +++ b/examples/tutorials/alarms/main.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include + +int main(int argc, char *argv[]) +{ + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + + QGuiApplication app(argc, argv); + + QQmlApplicationEngine engine; + engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + if (engine.rootObjects().isEmpty()) + return -1; + + return app.exec(); +} diff --git a/examples/tutorials/alarms/main.qml b/examples/tutorials/alarms/main.qml new file mode 100644 index 00000000..acd54168 --- /dev/null +++ b/examples/tutorials/alarms/main.qml @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.4 +import QtQuick.Layouts 1.11 +import QtQuick.Window 2.11 +import Qt.labs.calendar 1.0 + +ApplicationWindow { + id: window + width: 400 + height: 500 + visible: true + + ListView { + id: alarmListView + anchors.fill: parent + model: AlarmModel {} + delegate: AlarmDelegate {} + } + + RoundButton { + id: addAlarmButton + text: "+" + anchors.bottom: alarmListView.bottom + anchors.bottomMargin: 8 + anchors.horizontalCenter: parent.horizontalCenter + onClicked: alarmDialog.open() + } + + AlarmDialog { + id: alarmDialog + x: Math.round((parent.width - width) / 2) + y: Math.round((parent.height - height) / 2) + alarmModel: alarmListView.model + } +} diff --git a/examples/tutorials/alarms/qml.qrc b/examples/tutorials/alarms/qml.qrc new file mode 100644 index 00000000..ae9ac907 --- /dev/null +++ b/examples/tutorials/alarms/qml.qrc @@ -0,0 +1,10 @@ + + + main.qml + qtquickcontrols2.conf + TumblerDelegate.qml + AlarmModel.qml + AlarmDelegate.qml + AlarmDialog.qml + + diff --git a/examples/tutorials/alarms/qtquickcontrols2.conf b/examples/tutorials/alarms/qtquickcontrols2.conf new file mode 100644 index 00000000..3c676659 --- /dev/null +++ b/examples/tutorials/alarms/qtquickcontrols2.conf @@ -0,0 +1,5 @@ +[Controls] +Style=Material +[Material] +Theme=Dark +Accent=Red -- cgit v1.2.1