1

What I am trying to do is create this in Qml (w/o using any images):

Specification

It is a button that has:

  • a linear gradient as background
  • two borders
    • each has a width of 1px
    • the colors have an alpha, so the background will effect the actual visible color of each pixel
    • the outer border is above the general background of the application
    • the inner border is above the gradient
    • the colors of the inner and outer border of the left side is interchanged compared to the bottom and right border (i.e. color of inner border left = color of outer border bottom, etc.)
    • on the bottom left and bottom right (but not on the top!) there is a 3px radius

In CSS (the reference implementation is a browser single-page application) it is done with this code:

border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
box-shadow: rgba(152, 182, 219, 0.15) 0px 0px inset, rgba(2, 2, 4, 0.4) -1px 0px inset, rgba(2, 2, 4, 0.4) 0px -1px inset, rgba(152, 182, 219, 0.15) 1px 0px inset;
background: linear-gradient(rgb(47, 72, 99) 30%, rgb(36, 51, 71) 100%) padding-box;
border-bottom: 1px solid rgba(152, 182, 219, 0.15);
border-left: 1px solid rgba(2, 2, 4, 0.4);
border-right: 1px solid rgba(152, 182, 219, 0.15)

I am having trouble recreating this in Qml. As the radius property of the rectangle can only be set equal for all corners, I followed the idea mentioned in https://stackoverflow.com/a/39971599 . The result without using borders looks like this:

no borders

And this is the code I use for it:

Button {
    id: headerConfigButton
    // ...

    background: Rectangle {
        color: "transparent"

        Rectangle {
            height: headerConfigButton.height - headerConfigButtonLowerBackground.radius
            width: headerConfigButton.width
        }

        Rectangle {
            id: headerConfigButtonLowerBackground
            radius: 3
            height: headerConfigButton.height
            width: headerConfigButton.width
            color: "#242e3a"
        }

        LinearGradient {
            source: parent
            anchors.fill: parent
            start: Qt.point(0, 0)
            end: Qt.point(0, parent.height)
            gradient: Gradient {
                GradientStop {
                    position: 0.0
                    color: "#344a62"
                }
                GradientStop {
                    position: 1.0
                    color: "#293749"
                }
            }
        }
    }
}

Applying the borders was a little clumsy - I made a rectangle ("1px line") for each side and each border. Without the radius it looks like as in this picture:

no radius

Please note that the alpha values of the borders are not respected in this imgage; I found it easier to see what happens without using them.

The code for this:

Button {
    id: headerConfigButton
    // ...

    background: Rectangle {
        color: "transparent"

        Rectangle {  // left outer border
            width: 1
            height: headerConfigButton.height
            color: "#181e26"
        }

        Rectangle {  // left inner border
            x: 1
            width: 1
            height: headerConfigButton.height - 1
            color: "#4d637d"
        }

        Rectangle {  // bottom outer border
            x: 1
            y: headerConfigButton.height - 1
            width: headerConfigButton.width - 2
            height: 1
            color: "#344151"
        }

        Rectangle {  // bottom inner border
            x: 2
            y: headerConfigButton.height - 2
            width: headerConfigButton.width - 4
            height: 1
            color: "#181e26"
        }

        Rectangle {  // right inner border
            x: headerConfigButton.width - 2
            width: 1
            height: headerConfigButton.height - 1
            color: "#181e26"
        }

        Rectangle {  // right outer border
            x: headerConfigButton.width - 1
            width: 1
            height: headerConfigButton.height
            color: "#344151"
        }

        Rectangle {  // gradient fill
            id: headerConfigButtonGradientFill
            x: 2
            width: headerConfigButton.width - 4
            height: headerConfigButton.height - 2

            LinearGradient {
                source: parent
                anchors.fill: parent
                start: Qt.point(0, 0)
                end: Qt.point(0, parent.height)
                gradient: Gradient {
                    GradientStop {
                        position: 0.0
                        color: "#344a62"
                    }
                    GradientStop {
                        position: 1.0
                        color: "#293749"
                    }
                }
            }
        }
    }
}

But now I struggle to create the round corners in conjunction with the borders. One issue is that the color of the outer and inner borders are not the same on each side. In conjunction with the opacity of the border colors, I have no idea how to get the colors in the corners right. Additionally, the gradient needs to be cropped as well.

The colors of the gradient and borders shall be themeable later on. Thus, using a background image or recreating the corners pixel by pixel with fixed colors taken from the spec is not an option.

Has anyone got an idea how to solve this? Maybe I am completely off and there is a much better and easier way to do this?

Thanks in advance!

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
moerkb
  • 53
  • 4
  • That's a lot of Item for a single background. I'd recommend you to try doing it in c++ with a `QQuickItem` or `QQuickPaintedIntem`. If you can't do c++, maybe use `Canvas` instead ? – GrecKo Sep 28 '18 at 14:29
  • I would create an item using `QQuickItem` (or `QQuickPaintedItem`) and then use it as a background for the button using [Control.background](https://doc.qt.io/qt-5/qml-qtquick-controls2-control.html#background-prop) – folibis Sep 28 '18 at 14:32
  • Ok, then I can program it in C++, but I am still facing the same problem, i.e. combining the two borders with the radius and gradient, right? – moerkb Oct 01 '18 at 07:55

0 Answers0