~dblsaiko/k90s

7c14bac1f4373d8853d780a1314d9b267ddc9243 — 2xsaiko 3 years ago eb74caf master
Separate close and maximize/minimize buttons from the rest visually
6 files changed, 256 insertions(+), 19 deletions(-)

M appstyle/k90sstyl.cpp
M appstyle/k90sstyl.h
M deco/dbtngrup.cpp
M deco/dbtngrup.h
M deco/k90sdeco.cpp
M deco/k90sdeco.h
M appstyle/k90sstyl.cpp => appstyle/k90sstyl.cpp +4 -7
@@ 7,9 7,7 @@ K90sStyle::K90sStyle() : STYLE_CLASS() {

}

K90sStyle::~K90sStyle() {

}
K90sStyle::~K90sStyle() = default;

void K90sStyle::polish(QWidget* widget) {
    if (!widget) return;


@@ 23,10 21,6 @@ void K90sStyle::unpolish(QWidget* widget) {
    STYLE_CLASS::unpolish(widget);
}

QPalette K90sStyle::standardPalette() const {
    return STYLE_CLASS::standardPalette();
}

void K90sStyle::drawPrimitive(QStyle::PrimitiveElement pe, const QStyleOption* opt, QPainter* p, const QWidget* w) const {
    QCommonStyle::drawPrimitive(pe, opt, p, w);
}


@@ 43,6 37,9 @@ void K90sStyle::drawControl(QStyle::ControlElement element, const QStyleOption* 

    switch (element) {
        CALL_CAST(CE_PushButtonBevel, QStyleOptionButton, this->draw_button_frame(p, o, w))
        CALL_CAST(CE_PushButtonLabel, QStyleOptionButton, this->draw_button_label(p, o, w))
        CALL_CAST(CE_CheckBoxLabel, QStyleOptionButton, this->draw_checkbox_label(p, o, w))
        CALL_CAST(CE_RadioButtonLabel, QStyleOptionButton, this->draw_checkbox_label(p, o, w))

        default:
            QCommonStyle::drawControl(element, opt, p, w);

M appstyle/k90sstyl.h => appstyle/k90sstyl.h +4 -2
@@ 32,8 32,6 @@ public:

    void unpolish(QWidget* widget) override;

    QPalette standardPalette() const override;

    void drawPrimitive(PrimitiveElement pe, const QStyleOption* opt, QPainter* p, const QWidget* w) const override;

    void drawControl(ControlElement element, const QStyleOption* opt, QPainter* p, const QWidget* w) const override;


@@ 51,6 49,10 @@ public:
private:
    void draw_button_frame(QPainter* p, const QStyleOptionButton* opt, const QWidget* widget) const;

    void draw_button_label(QPainter* p, const QStyleOptionButton* opt, const QWidget* widget) const;

    void draw_checkbox_label(QPainter* p, const QStyleOptionButton* opt, const QWidget* widget) const;

};

#endif //K90S_K90SSTYL_H

M deco/dbtngrup.cpp => deco/dbtngrup.cpp +152 -0
@@ 1,1 1,153 @@
#include "dbtngrup.h"

#include <KDecoration2/DecorationSettings>
#include <utility>

using KDecoration2::Decoration;
using KDecoration2::DecorationButton;

DecorationButtonGroup::DecorationButtonGroup(
    ButtonPosition pos,
    std::function<DecorationButton*(DecorationButtonType, Decoration*, QObject*)> button_creator,
    Decoration* parent
) :
    QObject(parent),
    m_deco(parent),
    m_pos(pos),
    m_spacing(0),
    m_large_spacing(0),
    m_button_types(new quint8[static_cast<int>(DecorationButtonType::Custom) + 1] {}),
    m_button_creator(std::move(button_creator)),
    m_updating_geometry(false) //
{
    this->update_buttons();

    connect(
        parent->settings().data(),
        pos == POSITION_LEFT ?
        SIGNAL(decorationButtonsLeftChanged(const QVector<KDecoration2::DecorationButtonType>&)) :
        SIGNAL(decorationButtonsRightChanged(const QVector<KDecoration2::DecorationButtonType>&)),
        this,
        SLOT(update_buttons())
    );
}

DecorationButtonGroup::~DecorationButtonGroup() {
    delete[] this->m_button_types;
}

qreal DecorationButtonGroup::spacing() const {
    return this->m_spacing;
}

void DecorationButtonGroup::set_spacing(qreal spacing) {
    this->m_spacing = spacing;
    this->update_geometry();
}

qreal DecorationButtonGroup::large_spacing() const {
    return this->m_large_spacing;
}

void DecorationButtonGroup::set_large_spacing(qreal spacing) {
    this->m_large_spacing = spacing;
    this->update_geometry();
}

quint8 DecorationButtonGroup::category(DecorationButtonType type) {
    return this->m_button_types[static_cast<int>(type)];
}

void DecorationButtonGroup::set_category(DecorationButtonType type, quint8 category) {
    this->m_button_types[static_cast<int>(type)] = category;
    this->update_geometry();
}

QRectF DecorationButtonGroup::geometry() const {
    return this->m_geometry;
}

void DecorationButtonGroup::paint(QPainter* painter, const QRect& repaintArea) const {
    for (const auto& button: this->m_buttons) {
        if (!button->isVisible()) continue;

        button->paint(painter, repaintArea);
    }
}

void DecorationButtonGroup::update_geometry() {
    if (this->m_updating_geometry) return;
    this->m_updating_geometry = true;

    qreal cx = 0;
    qreal max_height = 0;
    QPointer<KDecoration2::DecorationButton> last;

    for (auto& button: this->m_buttons) {
        if (!button->isVisible()) continue;

        if (last) {
            if (this->category(last->type()) != this->category(button->type())) {
                cx += this->large_spacing();
            } else {
                cx += this->spacing();
            }
        }

        QRectF g = button->geometry();
        g.moveTo(this->geometry().left() + cx, this->geometry().top());
        button->setGeometry(g);

        max_height = qMax(max_height, g.height());
        cx += g.width();
        last = button;
    }

    QRectF g = this->geometry();
    g.setSize(QSizeF(cx, max_height));
    this->m_geometry = g;

    this->m_updating_geometry = false;
    emit this->geometry_changed(this->m_geometry);
}

void DecorationButtonGroup::update_buttons() {
    auto s = this->m_deco->settings();

    QVector<DecorationButtonType> buttons =
        this->m_pos == POSITION_LEFT ?
        s->decorationButtonsLeft() :
        s->decorationButtonsRight();

    qDeleteAll(this->m_buttons);
    this->m_buttons.clear();

    for (auto type: buttons) {
        DecorationButton* button = this->m_button_creator(type, this->m_deco, this);

        connect(button, SIGNAL(geometryChanged(const QRectF&)), this, SLOT(update_geometry()));
        connect(button, SIGNAL(visibilityChanged(bool)), this, SLOT(update_geometry()));

        this->m_buttons += button;
    }

    this->update_geometry();
}

const QVector<QPointer<KDecoration2::DecorationButton>>& DecorationButtonGroup::buttons() const {
    return this->m_buttons;
}

void DecorationButtonGroup::set_pos(const QPointF& top_left) {
    QPointF diff = top_left - this->m_geometry.topLeft();

    this->m_updating_geometry = true;

    for (auto& button: this->m_buttons) {
        button->setGeometry(button->geometry().translated(diff));
    }

    this->m_updating_geometry = false;

    this->m_geometry.setTopLeft(top_left);
}

M deco/dbtngrup.h => deco/dbtngrup.h +66 -0
@@ 1,4 1,70 @@
#ifndef K90SDECO_DBTNGRUP_H
#define K90SDECO_DBTNGRUP_H

#include <KDecoration2/Decoration>
#include <KDecoration2/DecorationButton>
#include <QBitArray>
#include <QObject>

using KDecoration2::DecorationButtonType;

enum ButtonPosition {
    POSITION_LEFT,
    POSITION_RIGHT,
};

class DecorationButtonGroup : public QObject {
Q_OBJECT

public:
    DecorationButtonGroup(
        ButtonPosition pos,
        std::function<KDecoration2::DecorationButton*(DecorationButtonType, KDecoration2::Decoration*, QObject*)> button_creator,
        KDecoration2::Decoration* parent
    );

    ~DecorationButtonGroup() override;

    void set_pos(const QPointF& top_left);

    qreal spacing() const;

    void set_spacing(qreal spacing);

    qreal large_spacing() const;

    void set_large_spacing(qreal spacing);

    quint8 category(DecorationButtonType type);

    void set_category(DecorationButtonType type, quint8 category);

    QRectF geometry() const;

    void paint(QPainter* painter, const QRect& repaintArea) const;

    const QVector<QPointer<KDecoration2::DecorationButton>>& buttons() const;

signals:

    void geometry_changed(const QRectF& geometry);

private slots:
    void update_geometry();

    void update_buttons();

private:
    KDecoration2::Decoration* m_deco;
    ButtonPosition m_pos;
    QRectF m_geometry;
    qreal m_spacing;
    qreal m_large_spacing;
    quint8* m_button_types;
    QVector<QPointer<KDecoration2::DecorationButton>> m_buttons;
    std::function<KDecoration2::DecorationButton*(DecorationButtonType, KDecoration2::Decoration*, QObject*)> m_button_creator;
    bool m_updating_geometry;

};

#endif //K90SDECO_DBTNGRUP_H

M deco/k90sdeco.cpp => deco/k90sdeco.cpp +25 -7
@@ 12,7 12,6 @@ using KDecoration2::ColorGroup;
using KDecoration2::ColorRole;
using KDecoration2::DecoratedClient;
using KDecoration2::Decoration;
using KDecoration2::DecorationButtonGroup;
using KDecoration2::DecorationButtonType;

K_PLUGIN_FACTORY_WITH_JSON(


@@ 43,15 42,28 @@ void K90sDecoration::init() {
    connect(c, SIGNAL(activeChanged(bool)), this, SLOT(update_title()));
    connect(c, SIGNAL(widthChanged(int)), this, SLOT(update_title_bar()));
    connect(c, SIGNAL(maximizedChanged(bool)), this, SLOT(update_title_bar()));
    connect(c, SIGNAL(maximizedChanged(bool)), this, SLOT(setOpaque(bool)));
    connect(c, SIGNAL(widthChanged(int)), this, SLOT(update_buttons_geometry()));
    connect(c, SIGNAL(widthChanged(int)), this, SLOT(update_buttons_geometry()));
    connect(c, SIGNAL(maximizedChanged(bool)), this, SLOT(update_buttons_geometry()));
    connect(c, SIGNAL(adjacentScreenEdgesChanged(Qt::Edges)), this, SLOT(update_buttons_geometry()));
    connect(c, SIGNAL(shadedChanged(bool)), this, SLOT(update_buttons_geometry()));

    this->m_left_buttons = new DecorationButtonGroup(DecorationButtonGroup::Position::Left, this, &K90sButton::create);
    this->m_right_buttons = new DecorationButtonGroup(DecorationButtonGroup::Position::Right, this, &K90sButton::create);
    this->m_left_buttons = new DecorationButtonGroup(POSITION_LEFT, &K90sButton::create, this);
    this->m_right_buttons = new DecorationButtonGroup(POSITION_RIGHT, &K90sButton::create, this);

    this->m_left_buttons->set_large_spacing(this->px_size() * 2);
    this->m_left_buttons->set_category(DecorationButtonType::Menu, 1);
    this->m_left_buttons->set_category(DecorationButtonType::Close, 2);
    this->m_left_buttons->set_category(DecorationButtonType::Minimize, 3);
    this->m_left_buttons->set_category(DecorationButtonType::Maximize, 3);
    this->m_right_buttons->set_large_spacing(this->px_size() * 2);
    this->m_right_buttons->set_category(DecorationButtonType::Menu, 1);
    this->m_right_buttons->set_category(DecorationButtonType::Close, 2);
    this->m_right_buttons->set_category(DecorationButtonType::Minimize, 3);
    this->m_right_buttons->set_category(DecorationButtonType::Maximize, 3);

    connect(this->m_left_buttons, SIGNAL(geometry_changed(const QRectF&)), this, SLOT(update_buttons_position()));
    connect(this->m_right_buttons, SIGNAL(geometry_changed(const QRectF&)), this, SLOT(update_buttons_position()));

    this->recalculate_borders();
    this->update_buttons_geometry();


@@ 137,7 149,6 @@ void K90sDecoration::update_title_bar() {
}

void K90sDecoration::update_buttons_geometry() {
    auto c = this->client().data();
    auto s = this->settings();

    for (const auto& button: this->m_left_buttons->buttons() + this->m_right_buttons->buttons()) {


@@ 146,6 157,13 @@ void K90sDecoration::update_buttons_geometry() {
        }
    }

    this->update();
}

void K90sDecoration::update_buttons_position() {
    auto c = this->client().data();
    auto s = this->settings();

    int border = this->effective_border_size(false);
    int extra_left = 0;
    int extra_right = 0;


@@ 162,8 180,8 @@ void K90sDecoration::update_buttons_geometry() {
        }
    }

    this->m_left_buttons->setPos(QPoint(border + extra_left, border));
    this->m_right_buttons->setPos(QPoint(
    this->m_left_buttons->set_pos(QPoint(border + extra_left, border));
    this->m_right_buttons->set_pos(QPoint(
        border + c->width() - (int) this->m_right_buttons->geometry().width() - extra_right,
        border
    ));

M deco/k90sdeco.h => deco/k90sdeco.h +5 -3
@@ 2,8 2,8 @@
#define K90SDECO_K90SDECO_H

#include <KDecoration2/Decoration>
#include <KDecoration2/DecorationButtonGroup>
#include <wintheme.h>
#include "dbtngrup.h"

class K90sDecoration : public KDecoration2::Decoration {
Q_OBJECT


@@ 33,6 33,8 @@ public slots:

    void update_buttons_geometry();

    void update_buttons_position();

private:
    inline bool is_maximized() const;



@@ 41,8 43,8 @@ private:
    int effective_border_size(bool bottom) const;

private:
    KDecoration2::DecorationButtonGroup* m_left_buttons;
    KDecoration2::DecorationButtonGroup* m_right_buttons;
    DecorationButtonGroup* m_left_buttons;
    DecorationButtonGroup* m_right_buttons;
    bool m_rescale;

};