forked from quickshell/quickshell
widgets: add ClippingRectangle
This commit is contained in:
parent
68ba5005ce
commit
fdc13023b7
9 changed files with 168 additions and 2 deletions
1
BUILD.md
1
BUILD.md
|
@ -41,6 +41,7 @@ Quickshell has a set of base dependencies you will always need, names vary by di
|
||||||
- `cmake`
|
- `cmake`
|
||||||
- `qt6base`
|
- `qt6base`
|
||||||
- `qt6declarative`
|
- `qt6declarative`
|
||||||
|
- `qtshadertools` (build-time only)
|
||||||
- `pkg-config`
|
- `pkg-config`
|
||||||
- `cli11`
|
- `cli11`
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ if (NOT CMAKE_BUILD_TYPE)
|
||||||
set(CMAKE_BUILD_TYPE Debug)
|
set(CMAKE_BUILD_TYPE Debug)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(QT_FPDEPS Gui Qml Quick QuickControls2 Widgets)
|
set(QT_FPDEPS Gui Qml Quick QuickControls2 Widgets ShaderTools)
|
||||||
|
|
||||||
include(cmake/pch.cmake)
|
include(cmake/pch.cmake)
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
cmake,
|
cmake,
|
||||||
ninja,
|
ninja,
|
||||||
qt6,
|
qt6,
|
||||||
|
spirv-tools,
|
||||||
cli11,
|
cli11,
|
||||||
breakpad,
|
breakpad,
|
||||||
jemalloc,
|
jemalloc,
|
||||||
|
@ -45,6 +46,8 @@
|
||||||
nativeBuildInputs = with pkgs; [
|
nativeBuildInputs = with pkgs; [
|
||||||
cmake
|
cmake
|
||||||
ninja
|
ninja
|
||||||
|
qt6.qtshadertools
|
||||||
|
spirv-tools
|
||||||
qt6.wrapQtAppsHook
|
qt6.wrapQtAppsHook
|
||||||
pkg-config
|
pkg-config
|
||||||
] ++ (lib.optionals withWayland [
|
] ++ (lib.optionals withWayland [
|
||||||
|
|
|
@ -1,10 +1,28 @@
|
||||||
qt_add_library(quickshell-widgets STATIC)
|
qt_add_library(quickshell-widgets STATIC
|
||||||
|
cliprect.cpp
|
||||||
|
)
|
||||||
|
|
||||||
qt_add_qml_module(quickshell-widgets
|
qt_add_qml_module(quickshell-widgets
|
||||||
URI Quickshell.Widgets
|
URI Quickshell.Widgets
|
||||||
VERSION 0.1
|
VERSION 0.1
|
||||||
QML_FILES
|
QML_FILES
|
||||||
IconImage.qml
|
IconImage.qml
|
||||||
|
ClippingRectangle.qml
|
||||||
|
)
|
||||||
|
|
||||||
|
qt6_add_shaders(quickshell-widgets "widgets-cliprect"
|
||||||
|
NOHLSL NOMSL BATCHABLE PRECOMPILE OPTIMIZED QUIET
|
||||||
|
PREFIX "/Quickshell/Widgets"
|
||||||
|
FILES shaders/cliprect.frag
|
||||||
|
OUTPUTS shaders/cliprect.frag.qsb
|
||||||
|
)
|
||||||
|
|
||||||
|
qt6_add_shaders(quickshell-widgets "widgets-cliprect-ub"
|
||||||
|
NOHLSL NOMSL BATCHABLE PRECOMPILE OPTIMIZED QUIET
|
||||||
|
PREFIX "/Quickshell/Widgets"
|
||||||
|
FILES shaders/cliprect.frag
|
||||||
|
OUTPUTS shaders/cliprect-ub.frag.qsb
|
||||||
|
DEFINES CONTENT_UNDER_BORDER
|
||||||
)
|
)
|
||||||
|
|
||||||
install_qml_module(quickshell-widgets)
|
install_qml_module(quickshell-widgets)
|
||||||
|
|
82
src/widgets/ClippingRectangle.qml
Normal file
82
src/widgets/ClippingRectangle.qml
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
///! Rectangle capable of clipping content inside its border.
|
||||||
|
/// > [!WARNING] This type requires at least Qt 6.7.
|
||||||
|
///
|
||||||
|
/// This is a specialized version of @@QtQuick.Rectangle that clips content
|
||||||
|
/// inside of its border, including rounded rectangles. It costs more than
|
||||||
|
/// @@QtQuick.Rectangle, so it should not be used unless you need to clip
|
||||||
|
/// items inside of it to the border.
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
/// If content should be displayed underneath the border.
|
||||||
|
///
|
||||||
|
/// Defaults to false, does nothing if the border is opaque.
|
||||||
|
property bool contentUnderBorder: false;
|
||||||
|
/// If the content item should be resized to fit inside the border.
|
||||||
|
///
|
||||||
|
/// Defaults to `!contentUnderBorder`. Most useful when combined with
|
||||||
|
/// `anchors.fill: parent` on an item passed to the ClippingRectangle.
|
||||||
|
property bool contentInsideBorder: !root.contentUnderBorder;
|
||||||
|
/// If the rectangle should be antialiased.
|
||||||
|
///
|
||||||
|
/// Defaults to true if any corner has a non-zero radius, otherwise false.
|
||||||
|
property /*bool*/alias antialiasing: rectangle.antialiasing;
|
||||||
|
/// The background color of the rectangle, which goes under its content.
|
||||||
|
property /*color*/alias color: shader.backgroundColor;
|
||||||
|
/// See @@QtQuick.Rectangle.border.
|
||||||
|
property clippingRectangleBorder border;
|
||||||
|
/// Radius of all corners. Defaults to 0.
|
||||||
|
property /*real*/alias radius: rectangle.radius
|
||||||
|
/// Radius of the top left corner. Defaults to @@radius.
|
||||||
|
property /*real*/alias topLeftRadius: rectangle.topLeftRadius
|
||||||
|
/// Radius of the top right corner. Defaults to @@radius.
|
||||||
|
property /*real*/alias topRightRadius: rectangle.topRightRadius
|
||||||
|
/// Radius of the bottom left corner. Defaults to @@radius.
|
||||||
|
property /*real*/alias bottomLeftRadius: rectangle.bottomLeftRadius
|
||||||
|
/// Radius of the bottom right corner. Defaults to @@radius.
|
||||||
|
property /*real*/alias borromRightRadius: rectangle.bottomRightRadius
|
||||||
|
|
||||||
|
/// Visual children of the ClippingRectangle's @@contentItem. (`list<Item>`).
|
||||||
|
///
|
||||||
|
/// See @@QtQuick.Item.children for details.
|
||||||
|
default property alias children: contentItem.children;
|
||||||
|
/// The item containing the rectangle's content.
|
||||||
|
/// There is usually no reason to use this directly.
|
||||||
|
readonly property alias contentItem: contentItem;
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: rectangle
|
||||||
|
anchors.fill: root
|
||||||
|
color: "#ffff0000"
|
||||||
|
border.color: "#ff00ff00"
|
||||||
|
border.pixelAligned: root.border.pixelAligned
|
||||||
|
border.width: root.border.width
|
||||||
|
layer.enabled: true
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: contentItemContainer
|
||||||
|
anchors.fill: root
|
||||||
|
layer.enabled: true
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: contentItem
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: root.contentInsideBorder ? root.border.width : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderEffect {
|
||||||
|
id: shader
|
||||||
|
anchors.fill: root
|
||||||
|
fragmentShader: `qrc:/Quickshell/Widgets/shaders/cliprect${root.contentUnderBorder ? "-ub" : ""}.frag.qsb`
|
||||||
|
property Rectangle rect: rectangle;
|
||||||
|
property color backgroundColor;
|
||||||
|
property color borderColor: root.border.color;
|
||||||
|
property Item content: contentItemContainer;
|
||||||
|
}
|
||||||
|
}
|
1
src/widgets/cliprect.cpp
Normal file
1
src/widgets/cliprect.cpp
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#include "cliprect.hpp" // NOLINT
|
20
src/widgets/cliprect.hpp
Normal file
20
src/widgets/cliprect.hpp
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qcolor.h>
|
||||||
|
#include <qmetaobject.h>
|
||||||
|
#include <qnamespace.h>
|
||||||
|
#include <qqmlintegration.h>
|
||||||
|
#include <qtmetamacros.h>
|
||||||
|
|
||||||
|
class ClippingRectangleBorder {
|
||||||
|
Q_GADGET;
|
||||||
|
Q_PROPERTY(QColor color MEMBER color);
|
||||||
|
Q_PROPERTY(bool pixelAligned MEMBER pixelAligned);
|
||||||
|
Q_PROPERTY(int width MEMBER width);
|
||||||
|
QML_VALUE_TYPE(clippingRectangleBorder);
|
||||||
|
|
||||||
|
public:
|
||||||
|
QColor color = Qt::black;
|
||||||
|
bool pixelAligned = true;
|
||||||
|
int width = 0;
|
||||||
|
};
|
|
@ -2,5 +2,6 @@ name = "Quickshell.Widgets"
|
||||||
description = "Bundled widgets"
|
description = "Bundled widgets"
|
||||||
qml_files = [
|
qml_files = [
|
||||||
"IconImage.qml",
|
"IconImage.qml",
|
||||||
|
"ClippingRectangle.qml",
|
||||||
]
|
]
|
||||||
-----
|
-----
|
||||||
|
|
40
src/widgets/shaders/cliprect.frag
Normal file
40
src/widgets/shaders/cliprect.frag
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#version 440
|
||||||
|
layout(location = 0) in vec2 qt_TexCoord0;
|
||||||
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
|
||||||
|
layout(std140, binding = 0) uniform buf {
|
||||||
|
mat4 qt_Matrix;
|
||||||
|
float qt_Opacity;
|
||||||
|
vec4 backgroundColor;
|
||||||
|
vec4 borderColor;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(binding = 1) uniform sampler2D rect;
|
||||||
|
layout(binding = 2) uniform sampler2D content;
|
||||||
|
|
||||||
|
vec4 overlay(vec4 base, vec4 overlay) {
|
||||||
|
if (overlay.a == 0.0) return base;
|
||||||
|
|
||||||
|
float baseMul = 1.0 - overlay.a;
|
||||||
|
float newAlpha = overlay.a + base.a * baseMul;
|
||||||
|
vec3 rgb = (overlay.rgb * overlay.a + base.rgb * base.a * baseMul) / newAlpha;
|
||||||
|
return vec4(rgb, newAlpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 contentColor = texture(content, qt_TexCoord0.xy);
|
||||||
|
vec4 rectColor = texture(rect, qt_TexCoord0.xy);
|
||||||
|
|
||||||
|
#ifdef CONTENT_UNDER_BORDER
|
||||||
|
float contentAlpha = rectColor.a;
|
||||||
|
#else
|
||||||
|
float contentAlpha = rectColor.r;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float borderAlpha = rectColor.g;
|
||||||
|
|
||||||
|
vec4 innerColor = overlay(backgroundColor, contentColor) * contentAlpha;
|
||||||
|
vec4 borderColor = borderColor * borderAlpha;
|
||||||
|
|
||||||
|
fragColor = (innerColor * (1.0 - borderColor.a) + borderColor) * qt_Opacity;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue