Zren / material-decoration

Material-ish window decoration theme for KWin, with LIM, based on zzag's original design.
GNU General Public License v2.0
197 stars 17 forks source link

1px Colored Window Borders #35

Closed giomatfois62 closed 3 years ago

giomatfois62 commented 3 years ago

Hi, I love your decoration and would like to add a narrow border (1pixel ideally) colored as the accent color when the window is focused. Something like windows10 does, as shown in this image

Screenshot (131)

with this it would be much easier to spot the currently focused window.

I tried hacking this feature in your code, reserving border space on titlebar creation and adding draw calls in the paint event, but I could not get it to work properly (settings window decorations page crashes on decoration preview load, so i must be doing something very wrong).

I'll keep experimenting on my own, but please consider adding this feature. And thanks for creating this awesome decoration!

Zren commented 3 years ago

Ah, I haven't implemented borders yet, so I should probably get around to that.

Use Breeze as an example. When the compositor is disabled, it draws an outline around the window. Just drop the if() {} statement wrapping the code in Decoration::paint().

I'll get around to implementing the configurable settings()->borderSize() once I decipher it. I looks like the breeze code also has a window specific override which is not part of the KDecoration API which I'll have to ignore.

giomatfois62 commented 3 years ago

thanks for looking into this and for the heads up on the implementation :) In the meantime, If I get something working on my own I'll send you a pull request just in case

Zren commented 3 years ago

Well, I needed to fix a segfault caused by an updateButtonGeometry() getting called before the button groups where initialized.

After simplifying Breeze's isLeftEdge() functions (is window touching left edge), binding to boderSizeChanged, and modifying updateBorders() I discovered that most of my titlebar code doesn't take borders into account.

Here's what it looks like when I comment out paintFrameBackground() then draw a 1px outline.

2021-03-04___22-00-28

void Decoration::paint(QPainter *painter, const QRect &repaintRegion)
{
    auto *decoratedClient = client().toStrongRef().data();

    if (!decoratedClient->isShaded()) {
        // paintFrameBackground(painter, repaintRegion);
    }

    paintTitleBarBackground(painter, repaintRegion);
    paintButtons(painter, repaintRegion);
    paintCaption(painter, repaintRegion);

    // Simple 1px border outline
    painter->save();
    painter->setRenderHint(QPainter::Antialiasing, false);
    painter->setBrush(Qt::NoBrush);
    painter->setPen(titleBarForegroundColor());
    painter->drawRect( rect().adjusted( 0, 0, -1, -1 ) );
    painter->restore();
}

void Decoration::updateBorders()
{
    const int sideSize = sideBorderSize();
    QMargins borders;
    borders.setTop(titleBarHeight());
    borders.setLeft(leftBorderVisible() ? sideSize : 0);
    borders.setRight(rightBorderVisible() ? sideSize : 0);
    borders.setBottom(bottomBorderVisible() ? bottomBorderSize() : 0);
    setBorders(borders);
}
giomatfois62 commented 3 years ago

Great Stuff! If I understood correctly from your snippets, to draw just the decoration outline one only needs this calls?

    // Simple 1px border outline
    painter->save();
    painter->setRenderHint(QPainter::Antialiasing, false);
    painter->setBrush(Qt::NoBrush);
    painter->setPen(titleBarForegroundColor());
    painter->drawRect( rect().adjusted( 0, 0, -1, -1 ) );
    painter->restore();

It would be already enough for my needs!

Zren commented 3 years ago

It's a bit more complicated than just drawing a rectangle. You need to change the left/right/bottom borders size, and doing so exposed a segfault bug when viewing the system monitor.

Here's my work in progress:

"Tiny" is a 1px line. With "Normal" being smallSpacing*1, instead of Breeze's smallSpacing*2 in thickness.

Right now I'm trying to fishing adjusting the left/right buttons, caption, and menu buttons offsets to account for the added borders as I can no longer assume the window contents are positioned at x=0 now that the left border pads it by a few pixels. I also need to decide if I want non-maximized windows should have the close button in the very top-right corner or if they should be pushed in to the left.

2021-03-05___15-58-45 2021-03-05___16-00-20 2021-03-05___15-57-37

Zren commented 3 years ago

To be honest, I'm not a fan of this much padding. I might use an offset for Oversized and use a padding for Tiny as it's just a 1px of padding. Or just forget the whole padding business.

2021-03-06___14-09-11 2021-03-06___14-08-41

Zren commented 3 years ago

The borders branch has been merged into master.

adrianinsaval commented 2 years ago

what color from the theme is used for the border? I would like to set a bright color for active windows and a dim color for inactive one's to make them easy to spot

Zren commented 2 years ago
    QColor outlineColor(titleBarForegroundColor());
    outlineColor.setAlphaF(0.25);
    const auto group = decoratedClient->isActive()
        ? KDecoration2::ColorGroup::Active
        : KDecoration2::ColorGroup::Inactive;
    return decoratedClient->color(group, KDecoration2::ColorRole::Foreground);
adrianinsaval commented 2 years ago

thanks, if I change this line: https://github.com/Zren/material-decoration/blob/e652d62451dc67a9c6bc16c00ccbc38fed3373dd/src/Decoration.cc#L1069 to have (0,0,-3,-3) will the outline be thicker or do I need something else?

What do you think of using the blend color for the outline instead of the foreground? That would allow to configure a more attention grabbing color like blue or green for the outline without making the text and buttons in the tittlebar look ugly. Just a suggestion, I will personally change the code to use the frame colors for my build.

Zren commented 2 years ago

rect().adjusted( 0, 0, -1, -1 ) takes the QRect(x,y,width,height) that represents the window frame, then subtracts 1 from the width and height so that when we draw the QRect stroke (aka outline), it will draw where we desire it to.

You need to set the pen.setWidthF(3); like in Button::setPenWidth(). You'll also probably need to adjusted(2, 2, -3, -3).

I just realized that the outline currently doesn't scale by DPI probably. 1080p and HiDPI both have an outline of 1px probably.