scene: Introduce z-property

This allows placing child items below their parent item by setting
negative Z values.
This commit is contained in:
Vlad Zahorodnii 2021-06-19 17:00:19 +03:00
parent 2a1f9f1646
commit 4ebe5d32b4
4 changed files with 82 additions and 6 deletions

View file

@ -39,6 +39,23 @@ Item::~Item()
}
}
int Item::z() const
{
return m_z;
}
void Item::setZ(int z)
{
if (m_z == z) {
return;
}
m_z = z;
if (m_parentItem) {
m_parentItem->markSortedChildItemsDirty();
}
scheduleRepaint(boundingRect());
}
Item *Item::parentItem() const
{
return m_parentItem;
@ -64,6 +81,8 @@ void Item::addChild(Item *item)
Q_ASSERT(!m_childItems.contains(item));
m_childItems.append(item);
markSortedChildItemsDirty();
updateBoundingRect();
scheduleRepaint(item->boundingRect().translated(item->position()));
}
@ -74,6 +93,7 @@ void Item::removeChild(Item *item)
scheduleRepaint(item->boundingRect().translated(item->position()));
m_childItems.removeOne(item);
markSortedChildItemsDirty();
updateBoundingRect();
}
@ -191,6 +211,7 @@ void Item::stackBefore(Item *sibling)
}
m_parentItem->m_childItems.move(selfIndex, selfIndex > siblingIndex ? siblingIndex : siblingIndex - 1);
markSortedChildItemsDirty();
scheduleRepaint(boundingRect());
sibling->scheduleRepaint(sibling->boundingRect());
@ -218,6 +239,7 @@ void Item::stackAfter(Item *sibling)
}
m_parentItem->m_childItems.move(selfIndex, selfIndex > siblingIndex ? siblingIndex + 1 : siblingIndex);
markSortedChildItemsDirty();
scheduleRepaint(boundingRect());
sibling->scheduleRepaint(sibling->boundingRect());
@ -237,6 +259,8 @@ void Item::stackChildren(const QList<Item *> &children)
#endif
m_childItems = children;
discardQuads();
markSortedChildItemsDirty();
}
void Item::scheduleRepaint(const QRegion &region)
@ -369,4 +393,24 @@ void Item::updateEffectiveVisibility()
}
}
static bool compareZ(const Item *a, const Item *b)
{
return a->z() < b->z();
}
QList<Item *> Item::sortedChildItems() const
{
if (!m_sortedChildItems.has_value()) {
QList<Item *> items = m_childItems;
std::stable_sort(items.begin(), items.end(), compareZ);
m_sortedChildItems = items;
}
return m_sortedChildItems.value();
}
void Item::markSortedChildItemsDirty()
{
m_sortedChildItems.reset();
}
} // namespace KWin

View file

@ -30,6 +30,9 @@ public:
QSize size() const;
void setSize(const QSize &size);
int z() const;
void setZ(int z);
/**
* Returns the enclosing rectangle of the item. The rect equals QRect(0, 0, width(), height()).
*/
@ -46,6 +49,7 @@ public:
Item *parentItem() const;
void setParentItem(Item *parent);
QList<Item *> childItems() const;
QList<Item *> sortedChildItems() const;
Scene::Window *window() const;
QPoint rootPosition() const;
@ -112,6 +116,7 @@ private:
void updateBoundingRect();
void scheduleRepaintInternal(const QRegion &region);
void reallocRepaints();
void markSortedChildItemsDirty();
bool computeEffectiveVisibility() const;
void updateEffectiveVisibility();
@ -122,10 +127,12 @@ private:
QRect m_boundingRect;
QPoint m_position;
QSize m_size = QSize(0, 0);
int m_z = 0;
bool m_visible = true;
bool m_effectiveVisible = true;
QVector<QRegion> m_repaints;
mutable std::optional<WindowQuadList> m_quads;
mutable std::optional<QList<Item *>> m_sortedChildItems;
};
} // namespace KWin

View file

@ -940,8 +940,18 @@ static WindowQuadList clipQuads(const Item *item, const OpenGLWindow::RenderCont
void OpenGLWindow::createRenderNode(Item *item, RenderContext *context)
{
item->preprocess();
const QList<Item *> sortedChildItems = item->sortedChildItems();
for (Item *childItem : sortedChildItems) {
if (childItem->z() >= 0) {
break;
}
if (childItem->isVisible()) {
createRenderNode(childItem, context);
}
}
item->preprocess();
if (auto shadowItem = qobject_cast<ShadowItem *>(item)) {
WindowQuadList quads = clipQuads(item, context);
if (!quads.isEmpty()) {
@ -985,8 +995,10 @@ void OpenGLWindow::createRenderNode(Item *item, RenderContext *context)
}
}
const QList<Item *> childItems = item->childItems();
for (Item *childItem : childItems) {
for (Item *childItem : sortedChildItems) {
if (childItem->z() < 0) {
continue;
}
if (childItem->isVisible()) {
createRenderNode(childItem, context);
}

View file

@ -245,18 +245,31 @@ void SceneQPainter::Window::performPaint(int mask, const QRegion &_region, const
void SceneQPainter::Window::renderItem(QPainter *painter, Item *item) const
{
item->preprocess();
const QList<Item *> sortedChildItems = item->sortedChildItems();
painter->save();
painter->translate(item->position());
for (Item *childItem : sortedChildItems) {
if (childItem->z() >= 0) {
break;
}
if (childItem->isVisible()) {
renderItem(painter, childItem);
}
}
item->preprocess();
if (auto surfaceItem = qobject_cast<SurfaceItem *>(item)) {
renderSurfaceItem(painter, surfaceItem);
} else if (auto decorationItem = qobject_cast<DecorationItem *>(item)) {
renderDecorationItem(painter, decorationItem);
}
const QList<Item *> childItems = item->childItems();
for (Item *childItem : childItems) {
for (Item *childItem : sortedChildItems) {
if (childItem->z() < 0) {
continue;
}
if (childItem->isVisible()) {
renderItem(painter, childItem);
}