Qt/QML - How to customize Popup dimming effect? - qt

Hi is there a way to customize the dimming effect of the Popup when modal === true? I want the surrounding area of the Popup to be dimmed more.

You can customize the dimming effect by overriding the Overlay.modal attached property. See the docs here
Popup {
id: popup
width: 400
height: 400
modal: true
visible: true
Overlay.modal: Rectangle {
color: "#aacfdbe7" // Use whatever color/opacity you like
}
}

Related

Qt QML Put element above a Drawer

I'm struggling with a very basic question..
Using QT 5.15.2:
We have a simple application with one main window and 2-3 sub-window (1 level down from main). The main window consists of a content item, a header and some menu-flaps distributed across the main window. So Far the sub-pages were opened with a drawer element.
However, the drawer overlays the flaps and header once opened and we need to re-instanciate the flaps and header within the drawer to have it visible. This is not really nice. Is there any way to define the z-level on which the drawer is opened? (apparently setting z doesn't work).
Item{
id: id_mainWindow
z: 0
Drawer{
id: id_subMenu1
anchors.fill: parent
z: 1
/* Not so nice workaround */
Button{
id: id_subClose
z: 100
onClicked{
id_subMenu1.close()
}
}
}
/* Unfortunately, this one gets hidden once, the drawer is open */
Button{
id: id_subOpenClose
z: 100
onClicked{
if( id_subMenu1.open ){
id_subMenu1.close()
} else {
id_subMenu1.open()
}
}
}
}
I would suggest that a Drawer is not the right component for this job as it is technically a Popup. It might be worth checking out the TabBar component instead.
Nevertheless here's a re-write of your code so that your Drawer opens without covering your id_subOpenClose button.
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Material
Rectangle {
id: id_mainWindow
anchors.fill: parent
Drawer {
id: id_subMenu1
/*
Set the Drawer's height and y position so that it does not cover your button
*/
y: id_subOpenClose.height
height: id_mainWindow.height - id_subOpenClose.height
width: id_mainWindow.width
// Do not dim background
dim: false
// Set this to zero if you want no shadow
Material.elevation: 2
edge: Qt.RightEdge
Label {
text: 'Hello World'
anchors.centerIn: parent
}
}
/*
This is your header button that was getting hidden
Here it stays as if it were part of a global header and does not get hidden by
the Drawer.
*/
Button{
id: id_subOpenClose
text: id_subMenu1.visible? 'close': 'open'
onClicked: id_subMenu1.visible? id_subMenu1.close(): id_subMenu1.open()
}
}
For an interactive WASM example of the above see here.

QML BusyIndicator how to overlay the current window, like ProgressDialog in Android

Iam using QML Busyindicator when a user login or loading a data in a page or something like this, I want to be able to make the busyindicator overlay over the current window and make the window not editable, something similar to the messagebox when it shows up and disables all the Window, so I cant interact with the widgets on this window until the loading finish, something like the ProgressDialog in Android.
this is my code and what I try to do, also I tried to use MessageDialog and use this indicator inside it and remove all buttons, but it does not work.
Popup {
id: waitpop
width: 100
height: 100
BusyIndicator {
id: login_progress
running: true
anchors.fill: parent
}
anchors.centerIn: Overlay.overlay
closePolicy: Popup.NoAutoClose
}
this code shows the busy indicator but the user still can interact with the button and text field and everything, so any ideas?
The modal property prevents you from being able to click outside the popup.
Popup {
anchors.centerIn: Overlay.overlay
closePolicy: Popup.NoAutoClose
modal: true
BusyIndicator {
running: true
}
}

WebEngineView + virtual keyboard - maintain scroll position after resizing (focused input)

I have a very simple browser app based on WebEngineView and virtual keyboard made in Qt Quick.
Everything works fine - the keyboard is shown perfectly each time I click on an input in the webview, but what bothers me is that if I click on an input that is at the bottom, the keyboard covers it after opening and I cannot see what I'm typing.
I tried solving it by resizing the WebEngineView element to accomodate for the keyboard height, like most mobile apps work. It works, I can scroll the page under the keyboard but the keyboard still covers the input and I need to scroll manually.
Is there any way I could adjust the web view scroll position so the keyboard doesn't cover the focused input from QML?
I cannot do it at a single website because I allow navigation to any website user wants, so I need some universal method.
Here is my qml code:
import QtQuick 2.12
import QtQuick.Window 2.12
import FreeVirtualKeyboard 1.0
import QtWebEngine 1.8
Window {
id: appContainer;
visible: true
width: 1280
height: 600
title: qsTr("WebEngineView")
property string pathUrl: "https://www.w3schools.com/html/html_forms.asp"
WebEngineView {
id: webview
width: appContainer.width
url: appContainer.pathUrl
height: appContainer.height
}
/*
Virtual keyboard
*/
InputPanel {
id: inputPanel
z: 99
y: appContainer.height
anchors.left: parent.left
anchors.right: parent.right
states: State {
name: "visible"
when: Qt.inputMethod.visible
PropertyChanges {
target: inputPanel
y: appContainer.height - inputPanel.height
}
}
transitions: Transition {
from: ""
to: "visible"
reversible: true
ParallelAnimation {
NumberAnimation {
properties: "y"
duration: 150
easing.type: Easing.InOutQuad
}
}
onRunningChanged: {
if(!running && inputPanel.state == "visible") {
// finished showing keyboard
webview.height = appContainer.height - inputPanel.height
console.log('Keyboard shown')
} else if(running && inputPanel.state != "visible") {
// begins to hide keyboard
webview.height = appContainer.height
console.log('Keyboard starts to hide');
}
}
}
}
}
So far the resizing part works okay - I do it in onRunningChanged so the webview resizes before the transition starts and after it ends - this prevents ugly empty space showing during transition.
Update
I have achieved the effect I wanted using webview.runJavaScript together with scrollIntoView after showing the keyboard:
webview.runJavaScript("document.activeElement.scrollIntoView({block: 'nearest', inline: 'nearest', behavior: 'smooth'})");
However I'm not sure if this is solution is the best, as I don't like the fact of involving javascript evaluation into the process. I'd like to know if there's any more "native" way of doing this.
Resize WebEngineView, scroll into view
The problem with resizing the WebEngineView is that HTML will see that your device screen suddenly shrunk and may decide to present a vastly different layout, for example move menu from top to side of the screen.
Even if this has not happened, layout has changed. The position on the new "screen" does not correspond to the position on the old one, there is no 1:1 relation, which is why it scrolls to a seemingly random spot in the first place.
We can tell webpage to scroll a focused element into view of new viewport:
If it was already onscreen than nothing happens.
If not, webpage scrolls so that the element fits on the screen if possible. scrollIntoView has parameters to scroll to the top/bottom of the screen as desired
So when onscreen keyboard is opened:
Save original scrollPosition
Resize WebEngineView
Optionally assign scrollPosition to saved value - although it probably won't do you any good
Use runJavaScript to determine activeElement and make it scrollIntoView
Repeat same steps when onscreen keyboard is dismissed.
Do not resize, scroll manually
Another approach would be to not resize the "screen" and just scroll the element into view if it got covered.
This would require Qt to change VisualViewport while leaving LayoutViewport intact (see this and this for more information) but it seems that Qt cannot do that, at least not through QML alone.
That leaves us with having to do it manually: determine position with getBoundingClientRect, calculate how much space does keyboard cover, and if it is not inside our calculated uncovered view area - scrollTo it.
(you will still need runJavaScript to get inside the webpage)
Perhaps this and this SO questions can help
Other options
#Hazelnutek reported some success with document.activeElement.scrollIntoViewIfNeeded()
Please see discussion in comments to this answer below:

What is the correct way to overlay an ActivityIndicator on BlackBerry 10?

In my BB10 application I wish to overlay an ActivityIndicator in the centre of the current screen to indicate when something (e.g. "loading") is happening.
My current solution is to embed such an indicator in the centre of a custom transparent dialog, as follows:
import bb.cascades 1.4
Dialog {
id: activityDialog
objectName: "activityDialog"
content: Container {
id: activityDialogContainer
horizontalAlignment: HorizontalAlignment.Center
verticalAlignment: VerticalAlignment.Center
// fully transparent background!
background: Color.create(0, 0, 0, 0)
layout: StackLayout {
}
ActivityIndicator {
id: theIndicator
preferredWidth: 500
preferredHeight: 500
}
Label {
id: activityLabel;
objectName: "activityLabel";
text: ""
horizontalAlignment: HorizontalAlignment.Center
verticalAlignment: VerticalAlignment.Center
}
}
onOpened: {
theIndicator.start();
}
onClosed: {
theIndicator.stop();
}
}
I can then simply open the dialog when I want to display the indicator.
The problem is that the dialog then prevents any interaction with the underlying Page's / NavigationPane's controls. I understand why. The dialog takes up the whole screen and although transparent still essentially hides any UI of the underlying pane.
How can I overlay an ActivityIndicator in the centre of the screen without preventing interaction with the underlying panel's controls?
I now realised I simply need to create a DockLayout around my main Container and the ActivityIndicator.

QML OnHighligt movement completed

I have this ListView:
ListView {
id: topList
focus: true
width: parent.width
height: parent.height
preferredHighlightBegin: height - 70
preferredHighlightEnd: height
highlightMoveSpeed: 150
highlight: Rectangle { width: theListView.width; height: 22; color: "yellow" }
highlightRangeMode: ListView.StrictlyEnforceRange
}
Now, when I use up or down arrow the list moves nice and fine. However, when the movement is done, I would like to trigger another animation. Have tried listening on onMovementEnded and onFlickEnded but neither of them seems to be triggered when the animation is done.
The QtQuick examples include an example of rolling your own: http://doc.qt.nokia.com/4.7-snapshot/declarative-modelviews-listview-highlight-qml.html
The basic idea is to prevent the view from moving the highlight itself:
highlightFollowsCurrentItem: false
and use an animation to make the highlight follow the currentItem. You will probably want to stick to SmoothedAnimation or SpringAnimation since they handle the target position being moved before the animation is complete.
I believe it is not possible. highlightPosAnimator and highlightSizeAnimator are part of QDeclarativeListView private implementation, and not accesible by "user" code.
If you need custom/combined highlight animation, looks like you have to roll your own.

Resources