How to do an opacity gradient in an image? - qt

I have implemented a cover flow similar to Itunes. But there is still one thing that I can't solve, even after researching and reading the documentation...
I have the following result, but I would like to display only half of the reflection.
I have found the following StackOverflow post : How do I make a gradient opacity in an image - QML which is very similar to what I would like to achieve. Except that as my background is a gradient, I can't select the white color (or any plain color for the last GradientStop element in the solution code offered as solution).
Here is my code so far:
Image {
id: rectDelegate
anchors.fill: parent
source: images[index % images.length]
}
ShaderEffectSource {
id: reflection
sourceItem: rectDelegate
y: sourceItem.height
width: sourceItem.width
height: sourceItem.height
transform: [
Rotation {
origin.x: reflection.width / 2
origin.y: reflection.height / 2
axis.x: 1
axis.y: 0
axis.z: 0
angle: 180
}
]
visible: reflection_visible
}
Rectangle {
anchors.fill: reflection
gradient: Gradient {
GradientStop {
position: 0.0
color: "#55ffffff"
}
GradientStop {
// This determines the point at which the reflection fades out.
position: 1
color: "#ffffff"
}
}
visible: reflection_visible
}
I tried to embed the ShaderEffectSource element inside a transparent rectangle whose height would be half of the reflection height and to clip the ShaderEffectSource inside, but the reflection wouldn't appear :/
Here is the code :
Rectangle {
anchors.top: rectDelegate.bottom
color: "transparent"
width: rectDelegate.width
height: rectDelegate.height - 300
visible: reflection_visible
clip: true
border.color: "yellow"
ShaderEffectSource {
id: reflection
sourceItem: rectDelegate
y: sourceItem.height
width: sourceItem.width
height: sourceItem.height
transform: [
Rotation {
origin.x: reflection.width / 2
origin.y: reflection.height / 2
axis.x: 1
axis.y: 0
axis.z: 0
angle: 180
}
]
visible: reflection_visible
}
}
Any idea would be welcome :) I tried to make my post as clear as possible but if there is something missing for understanding, please, ask :)

read this post:
How do I make a gradient opacity in an image? - QML
or you can use Canvas type to draw your image with transparent gradient , but the proper way is the first one.

Related

For QML, why LayoutMirroring doesn't work in Slider?

Today I tried the Slider in QtQuick.Controls, my slider is left to right, I want to set my slider as from right to left by using LayoutMirroring.enabled, at last I found I cann't inverted the slider.
Here is my little demo code, so how can we invert a slider?
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Slider{
id:test
value: 0.2
width:400
LayoutMirroring.enabled: true
}
}
If you use the Slider from QtQuick.Controls 2.x - at least for me - it works like a charm. If you use the Slider from QtQuick.Controls 1.x it does not.
From the documentation:
Keep in mind, however, that mirroring does not affect any positioning that is defined by the Item x coordinate value, so even with mirroring enabled, it will often be necessary to apply some layout fixes to support the desired layout direction.
The QtQuick.Controls 1.x-Slider however uses a largely coordinate based implementation and has no further precautions to support the LayoutMirroring.
However the Sliders layout is usually symetrically, so all you need to do is to map the values like from (0,1) to (1,0). This should be a easy task to a developer.
import QtQuick.Controls 1.3
import QtQuick.Controls.Layouts 1.3
import QtQuick.Controls.Private 1.3 // Needed for a mysterious value from the original, now mirrored style.
Slider {
y: 40
id: sli
width: parent.width
minimumValue: 50
maximumValue: 100
property real mirroredValue: maximumValue - value + minimumValue
// Invert style
style: SliderStyle {
groove: Item {
property color fillColor: "#49d"
anchors.verticalCenter: parent.verticalCenter
// Whatever TextSingleton is. You need to import QtQuick.Controls.Private 1.x for it.
implicitWidth: Math.round(TextSingleton.implicitHeight * 4.5)
implicitHeight: Math.max(6, Math.round(TextSingleton.implicitHeight * 0.3))
Rectangle {
radius: height/2
anchors.fill: parent
border.width: 1
border.color: "#888"
gradient: Gradient {
GradientStop { color: "#bbb" ; position: 0 }
GradientStop { color: "#ccc" ; position: 0.6 }
GradientStop { color: "#ccc" ; position: 1 }
}
}
Item {
clip: true
x: styleData.handlePosition // let the fill-stuff start at the handle position...
width: parent.width - styleData.handlePosition // and end at the end of the groove.
height: parent.height
Rectangle {
anchors.fill: parent
border.color: Qt.darker(fillColor, 1.2)
radius: height/2
gradient: Gradient {
GradientStop {color: Qt.lighter(fillColor, 1.3) ; position: 0}
GradientStop {color: fillColor ; position: 1.4}
}
}
}
}
}
}
If you wan't to set the value of your slider, you need to install a bidirectional binding between mirroredValue and value.
I had a similar problem. My slider was vertical with values increasing from bottom to the top. I wanted them to increase from top to bottom. I accomplished it using rotation. I think that you could have solved your problem like this:
Slider {
id: test
value: 0.2
width: 400
rotation: 180 // This should make the slider right-to-left
}

Linear Gradient along x-axis not working. QML Qt 5.7

I need to apply Linear Gradient along x-axis in my project. But it doesn't seem to work. Even with the simplest code, that is from Qt documentation of Linear Gradient right away, it doesn't show the expected output.
Here's my code.
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Item {
width: 300
height: 300
LinearGradient {
anchors.fill: parent
end: Qt.point(300, 0)
start: Qt.point(0, 0)
gradient: Gradient {
GradientStop { position: 0.0; color: "white" }
GradientStop { position: 1.0; color: "black" }
}
}
}}
My code produces this output.
Anyone has any idea about what's going on. Please help. Thanks in advance.
It's weird, I'm using 2.5 version and I have the correct output...
Anyway, you still can define your gradient vertically and apply a rotation
end: Qt.point(0, 300)
start: Qt.point(0, 0)
rotation: -90

Is there any way to specify different radii for different corners

Can anyone help me how to round only one corner of a rectangle like shown in attached pic where red rectangle is my child rectangle.
Actually, I have a rectangle where all four corners rounded(radius 10). Now, i want to draw a new rectangle inside this and expecting only that particular corner should be rounded who touches the parent's round corner.
Rectangle
{
id: parent
radius: 10
width: 168
height: 168
visible: true
color: "black"
Rectangle
{
id: child
width: 100
height: 40
color: "red"
}
}
I tried to do this with adding clip property in child but nothing happened.
Here is a simple example.
It is rounded in the upper left corner, but is easily adjusted to any other corner. Only one corner is supported in this solution, but it might be enough for you?
More corners are little more complex, so ask again if you would need those aswell.
Rectangle {
anchors.centerIn: parent
id: root
radius: 20
width: 300
height: 300
Rectangle {
id: clipper
width: 100
height: 100
color: 'transparent'
clip: true
Rectangle {
id: clipped
width: parent.width + radius
height: parent.height + radius
radius: root.radius
color: 'red'
}
}
}
Not with the stock Rectangle:
The same radius is used by all 4 corners; there is currently no way to
specify different radii for different corners.
In C++ you could specify a horizontal and vertical radius, but still not per-corner radius. If you want such functionality, you will have to implement your own QQuickItem with the geometry node and all.
The result you want to achieve in the image could also be achieved with clipping, however unfortunately, in QML clipping only works for the item's rectangle, not the actual item geometry.
It will be easiest to achieve the desired effect using a BorderImage element. It enables to specify a different sub-image for every corner:
It is possible using Shape item as below:
Shape {
id: advancedShape
width: 100; height: 40
vendorExtensionsEnabled: true
layer.enabled: true
layer.samples: 4
layer.smooth: true
// set following properties to specify radius
property real tlRadius: 0.0
property real trRadius: 15.0
property real brRadius: 0.0
property real blRadius: 0.0
ShapePath {
strokeColor: "transparent"
fillColor: "red"
startX: 0; startY: advancedShape.tlRadius
PathArc {
x: advancedShape.tlRadius; y: 0
radiusX: advancedShape.tlRadius; radiusY: advancedShape.tlRadius
useLargeArc: false
}
PathLine {
x: advancedShape.width - advancedShape.trRadius; y: 0
}
PathArc {
x: advancedShape.width; y: advancedShape.trRadius
radiusX: advancedShape.trRadius; radiusY: advancedShape.trRadius
useLargeArc: false
}
PathLine {
x: advancedShape.width; y: advancedShape.height - advancedShape.brRadius
}
PathArc {
x: advancedShape.width - advancedShape.brRadius; y: advancedShape.height
radiusX: advancedShape.brRadius; radiusY: advancedShape.brRadius
useLargeArc: false
}
PathLine {
x: advancedShape.blRadius; y: advancedShape.height
}
PathArc {
x: 0; y: advancedShape.height - advancedShape.blRadius
radiusX: advancedShape.blRadius; radiusY: advancedShape.blRadius
useLargeArc: false
}
PathLine {
x: 0; y: advancedShape.tlRadius
}
}
}
and result will be as this:
NOTE The builtin Rectangle has more performance than Shape, but I recommend Shape over masking because it works on any environment.
NOTE 2 I think the most true way in production is using BorderImage as #dtech suggested IF the radius is known and you don't need to change radius dynamically.
Created this from a bunch of rectangles. Two big rectangles and 4 smaller optionally rounded squares. This way you can also make different radii for each corner, not only turning them on and off. You just need to make sure that you don't want a too big rounding, because then the rounded rect would stick out.
Rectangle {
id: clipper
width: 10
height: 10
color: "transparent"
clip: true
Rectangle {
id: clipped
width: 30
height: 30
radius: 8
color: "red"
}
}

QML : Flippable issue

I am trying to make a flippable clock in QML.
But am not able to get the flippable effect as desired, I have referred the documentation of flip method, took that as base for further development.
Tried various approaches but didn't succeed. Any idea how to get that effect.
Below is the referred documentation code snippet
import QtQuick 1.0
Flipable {
id: flipable
width: 240
height: 240
property bool flipped: false
front: Image { source: "front.png"; anchors.centerIn: parent }
back: Image { source: "back.png"; anchors.centerIn: parent }
transform: Rotation {
id: rotation
origin.x: flipable.width/2
origin.y: flipable.height/2
axis.x: 1; axis.y: 0; axis.z: 0 // set axis.x to 1 to rotate around y-axis
angle: 0 // the default angle
}
states: State {
name: "back"
PropertyChanges { target: rotation; angle: 180 }
when: flipable.flipped
}
transitions: Transition {
NumberAnimation { target: rotation; property: "angle"; duration: 4000 }
}
MouseArea {
anchors.fill: parent
onClicked: flipable.flipped = !flipable.flipped
}
}
You can't flip just half of an Item. To simulate a flip clock you have to use two clones of an image.
Try to add this at the end of the code above:
Item {
anchors {top: flipable.top; horizontalCenter: flipable.horizontalCenter}
width: flipable.width
height: flipable.height / 2
z: flipable.z + 1
clip: true
Image {
source: "front.png";
anchors.centerIn: parent
}
}
Obviously this code is not the solution, it's just a hint on what you have to do for the complete solution.

QML gradients with an orientation

QML gradient allows only from top to bottom in a Rectangle. The documentation says that
it has to be done through combination of rotation and clipping.
I have just started learning QML (and little experience with HTML/CSS). Here is my code which I think can be improved for a lot better:
import QtQuick 1.0
Rectangle {
width: 400; height: 400;
Rectangle {
width: 567; height: 567;
gradient: Gradient {
GradientStop {
position: 0.0;
color: "white";
}
GradientStop {
position: 1.0;
color: "blue";
}
}
x: 116.5;
transformOrigin: Item.Top;
rotation: 45.0;
}
}
Can you please suggest what are the better ways to do this?
I've solve this probling with the following code: https://code.google.com/p/ytd-meego/source/browse/trunk/playground/FeedBook/qmltube/HorizontalGradient.qml?r=144
Here is what I've done using the example of NielsMayer:
Rectangle {
width: parent.height
height: parent.width
anchors.centerIn: parent
rotation: 90
gradient: Gradient {
GradientStop { position: 0.0; color: "black" }
GradientStop { position: 1.0; color: "white" }
}
}
And this is working well. Have fun !
The Qt Graphical Effects module introduced in Qt 5.1 provides three gradient types.
With the LinearGradient item (effect) it is no longer necessary to apply rotation in order to achieve e.g. a horizontal color gradient.
In particular by means of the start and end point (attributes) of LinearGradient any gradient direction is possible.
The following code implements a 45° angle (as proposed in the original post) by starting top right with white and ending bottom left with black:
import QtQuick 2.0
import QtGraphicalEffects 1.0
Item {
id:myItem
width: 300
height: 300
LinearGradient {
anchors.fill: parent
start: Qt.point(myItem.width, 0)
end: Qt.point(0, myItem.height)
gradient: Gradient {
GradientStop { position: 0.0; color: "white" }
GradientStop { position: 1.0; color: "black" }
}
}
}
I'm afraid the documentation is correct.
The only other way I can think of is to write a custom QML component in C++ which does what you want.
If you have Qt/C++ knowledge you could start here:
http://doc.qt.nokia.com/4.7-snapshot/qml-extending.html
http://doc.qt.nokia.com/4.7-snapshot/declarative-tutorials-extending-chapter1-basics.html
The Rectangle could be a good template or base class:
http://qt.gitorious.org/qt/qt/blobs/4.8/src/declarative/graphicsitems/qdeclarativerectangle_p.h
You can use the orientation property from Qt 5.12

Resources