mirror of
https://github.com/Trensa-Organization/hy3.git
synced 2025-03-15 18:53:40 +01:00
Replace tab entry logic and tab bar renderer (WIP)
This commit is contained in:
parent
5d6b415c7f
commit
45a9721702
2 changed files with 181 additions and 118 deletions
258
src/TabGroup.cpp
258
src/TabGroup.cpp
|
@ -5,86 +5,151 @@
|
|||
#include <hyprland/src/Compositor.hpp>
|
||||
#include <cairo/cairo.h>
|
||||
|
||||
void Hy3TabBar::updateWithGroupEntries(Hy3Node& group_node) {
|
||||
if (group_node.data.type != Hy3NodeData::Group) return;
|
||||
auto& group = group_node.data.as_group;
|
||||
Hy3TabBarEntry::Hy3TabBarEntry(Hy3TabBar& tab_bar, Hy3Node& node): tab_bar(tab_bar), node(node) {
|
||||
this->offset.create(AVARTYPE_FLOAT, -1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), nullptr, AVARDAMAGE_NONE);
|
||||
this->width.create(AVARTYPE_FLOAT, -1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), nullptr, AVARDAMAGE_NONE);
|
||||
|
||||
auto entries_iter = this->entries.begin();
|
||||
auto group_iter = group.children.begin();
|
||||
this->offset.registerVar();
|
||||
this->width.registerVar();
|
||||
|
||||
auto* root_node = &group_node;
|
||||
while (root_node->parent != nullptr) root_node = root_node->parent;
|
||||
Hy3Node* focused_node = root_node->getFocusedNode();
|
||||
this->window_title = node.getTitle();
|
||||
this->urgent = node.isUrgent();
|
||||
}
|
||||
|
||||
while (entries_iter != this->entries.end()) {
|
||||
if (group_iter == group.children.end()) {
|
||||
needs_redraw = true;
|
||||
bool Hy3TabBarEntry::operator==(const Hy3Node& node) const {
|
||||
return this->node == node;
|
||||
}
|
||||
|
||||
while (entries_iter != this->entries.end()) {
|
||||
entries_iter = this->entries.erase(entries_iter);
|
||||
}
|
||||
Hy3TabBar::Hy3TabBar() {
|
||||
this->vertical_pos.create(AVARTYPE_FLOAT, 20.0f, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), nullptr, AVARDAMAGE_NONE);
|
||||
this->fade_opacity.create(AVARTYPE_FLOAT, 0.0f, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), nullptr, AVARDAMAGE_NONE);
|
||||
this->focus_start.create(AVARTYPE_FLOAT, 0.0f, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), nullptr, AVARDAMAGE_NONE);
|
||||
this->focus_end.create(AVARTYPE_FLOAT, 1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), nullptr, AVARDAMAGE_NONE);
|
||||
this->vertical_pos.registerVar();
|
||||
this->fade_opacity.registerVar();
|
||||
this->focus_start.registerVar();
|
||||
this->focus_end.registerVar();
|
||||
|
||||
return;
|
||||
};
|
||||
this->vertical_pos = 0.0;
|
||||
this->fade_opacity = 1.0;
|
||||
}
|
||||
|
||||
auto& entry = *entries_iter;
|
||||
auto& node = **group_iter;
|
||||
void Hy3TabBar::focusNode(Hy3Node* node) {
|
||||
this->focused_node = node;
|
||||
|
||||
std::string title = node.getTitle();
|
||||
bool urgent = node.isUrgent();
|
||||
bool focused = focused_node == &group_node
|
||||
|| focused_node == &node
|
||||
|| (node.data.type == Hy3NodeData::Group && node.data.as_group.hasChild(focused_node));
|
||||
if (this->focused_node == nullptr) {
|
||||
this->focus_start = 0.0;
|
||||
this->focus_end = 1.0;
|
||||
} else {
|
||||
auto entry = std::find(this->entries.begin(), this->entries.end(), *node);
|
||||
|
||||
if (entry.urgent != urgent
|
||||
|| entry.focused != focused
|
||||
|| entry.window_title != title)
|
||||
this->needs_redraw = true;
|
||||
|
||||
entry.window_title = std::move(title);
|
||||
entry.urgent = urgent;
|
||||
entry.focused = focused;
|
||||
|
||||
entries_iter = std::next(entries_iter);
|
||||
group_iter = std::next(group_iter);
|
||||
}
|
||||
|
||||
while (group_iter != group.children.end()) {
|
||||
needs_redraw = true;
|
||||
|
||||
auto& node = **group_iter;
|
||||
|
||||
this->entries.push_back({
|
||||
.window_title = node.getTitle(),
|
||||
.urgent = node.isUrgent(),
|
||||
.focused = focused_node == &group_node
|
||||
|| focused_node == &node
|
||||
|| (node.data.type == Hy3NodeData::Group && node.data.as_group.hasChild(focused_node)),
|
||||
});
|
||||
|
||||
group_iter = std::next(group_iter);
|
||||
if (entry != this->entries.end()) {
|
||||
this->focus_start = entry->offset.goalf();
|
||||
this->focus_end = entry->offset.goalf() + entry->width.goalf();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Hy3TabBar::setPos(Vector2D pos) {
|
||||
if (pos == this->pos) return;
|
||||
needs_redraw = true;
|
||||
this->pos = pos;
|
||||
void Hy3TabBar::updateNodeList(std::list<Hy3Node*>& nodes) {
|
||||
std::list<Hy3TabBarEntry> removed_entries;
|
||||
|
||||
auto entry = this->entries.begin();
|
||||
auto node = nodes.begin();
|
||||
|
||||
// move any out of order entries to removed_entries
|
||||
while (node != nodes.end()) {
|
||||
while (true) {
|
||||
if (entry == this->entries.end()) goto exitloop;
|
||||
if (*entry == **node) break;
|
||||
removed_entries.splice(removed_entries.end(), this->entries, entry++);
|
||||
}
|
||||
|
||||
node = std::next(node);
|
||||
entry = std::next(entry);
|
||||
}
|
||||
|
||||
exitloop:
|
||||
|
||||
// move any extra entries to removed_entries
|
||||
removed_entries.splice(removed_entries.end(), this->entries, entry, this->entries.end());
|
||||
|
||||
entry = this->entries.begin();
|
||||
node = nodes.begin();
|
||||
|
||||
// add missing entries, taking first from removed_entries
|
||||
while (node != nodes.end()) {
|
||||
if (entry == this->entries.end() || *entry != **node) {
|
||||
auto moved = std::find(removed_entries.begin(), removed_entries.end(), **node);
|
||||
if (moved != removed_entries.end()) {
|
||||
this->entries.splice(std::next(entry), removed_entries, moved);
|
||||
entry = moved;
|
||||
} else {
|
||||
entry = this->entries.insert(std::next(entry), Hy3TabBarEntry(*this, **node));
|
||||
}
|
||||
}
|
||||
|
||||
node = std::next(node);
|
||||
if (entry != this->entries.end()) entry = std::next(entry);
|
||||
}
|
||||
|
||||
// initiate remove animations for any removed entries
|
||||
for (auto& entry: removed_entries) {
|
||||
// TODO: working entry remove anim
|
||||
entry.width = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void Hy3TabBar::updateAnimations(bool warp) {
|
||||
int active_entries = 0;
|
||||
for (auto& entry: this->entries) {
|
||||
if (entry.width.goalf() != 0.0) active_entries++;
|
||||
}
|
||||
|
||||
float entry_width = active_entries == 0 ? 0.0 : 1.0 / active_entries;
|
||||
float offset = 0.0;
|
||||
|
||||
auto entry = this->entries.begin();
|
||||
while (entry != this->entries.end()) {
|
||||
if (warp && entry->width.goalf() == 0.0) {
|
||||
this->entries.erase(entry++);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto warp_init = entry->offset.goalf() == -1.0;
|
||||
entry->offset = offset;
|
||||
|
||||
if (warp_init) {
|
||||
entry->offset.warp();
|
||||
entry->width.setValueAndWarp(0.0);
|
||||
}
|
||||
|
||||
entry->width = entry_width;
|
||||
offset += entry_width;
|
||||
|
||||
entry = std::next(entry);
|
||||
}
|
||||
}
|
||||
|
||||
void Hy3TabBar::setSize(Vector2D size) {
|
||||
if (size == this->size) return;
|
||||
this->need_mask_redraw = true;
|
||||
this->size = size;
|
||||
}
|
||||
|
||||
void Hy3TabBar::prepareTexture() {
|
||||
auto bar_width = this->size.x;
|
||||
auto bar_height = this->size.y;
|
||||
void Hy3TabBar::prepareMask() {
|
||||
static const auto* rounding_setting = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:rounding")->intValue;
|
||||
auto rounding = *rounding_setting;
|
||||
|
||||
if (needs_redraw || this->texture.m_iTexID == 0) {
|
||||
static const auto* rounding_setting = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:rounding")->intValue;
|
||||
auto rounding = *rounding_setting;
|
||||
auto width = this->size.x;
|
||||
auto height = this->size.y;
|
||||
|
||||
auto cairo_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, this->size.x, this->size.y);
|
||||
if (this->need_mask_redraw
|
||||
|| this->last_mask_rounding != rounding
|
||||
|| this->mask_texture.m_iTexID == 0
|
||||
) {
|
||||
this->last_mask_rounding = rounding;
|
||||
|
||||
auto cairo_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
|
||||
auto cairo = cairo_create(cairo_surface);
|
||||
|
||||
// clear pixmap
|
||||
|
@ -93,48 +158,28 @@ void Hy3TabBar::prepareTexture() {
|
|||
cairo_paint(cairo);
|
||||
cairo_restore(cairo);
|
||||
|
||||
auto swidth = (double) bar_width / (double) this->entries.size();
|
||||
size_t i = 0;
|
||||
// set brush
|
||||
cairo_set_source_rgba(cairo, 0.2, 0.7, 1.0, 0.5);
|
||||
cairo_set_line_width(cairo, 2.0);
|
||||
|
||||
for (auto& entry: this->entries) {
|
||||
auto width = swidth;
|
||||
auto x = i * width;
|
||||
// outline bar shape
|
||||
cairo_move_to(cairo, 0, rounding);
|
||||
cairo_arc(cairo, rounding, rounding, rounding, -180.0 * (M_PI / 180.0), -90.0 * (M_PI / 180.0));
|
||||
cairo_line_to(cairo, width - rounding, 0);
|
||||
cairo_arc(cairo, width - rounding, rounding, rounding, -90.0 * (M_PI / 180.0), 0.0);
|
||||
cairo_line_to(cairo, width, height - rounding);
|
||||
cairo_arc(cairo, width - rounding, height - rounding, rounding, 0.0, 90.0 * (M_PI / 180.0));
|
||||
cairo_line_to(cairo, rounding, height);
|
||||
cairo_arc(cairo, rounding, height - rounding, rounding, -270.0 * (M_PI / 180.0), -180.0 * (M_PI / 180.0));
|
||||
cairo_close_path(cairo);
|
||||
|
||||
if (entry.focused) {
|
||||
cairo_set_source_rgba(cairo, 0.0, 1.0, 0.7, 0.5);
|
||||
} else {
|
||||
cairo_set_source_rgba(cairo, 0.2, 0.7, 1.0, 0.5);
|
||||
}
|
||||
|
||||
if (i == this->entries.size() - 1) {
|
||||
cairo_move_to(cairo, x + width - rounding, rounding);
|
||||
cairo_arc(cairo, x + width - rounding, rounding, rounding, -90.0 * (M_PI / 180.0), 0.0);
|
||||
cairo_rectangle(cairo, x + width - rounding, rounding, rounding, bar_height - rounding * 2);
|
||||
cairo_move_to(cairo, x + width - rounding, bar_height - rounding);
|
||||
cairo_arc(cairo, x + width - rounding, bar_height - rounding, rounding, 0.0, 90.0 * (M_PI / 180.0));
|
||||
width -= rounding;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
cairo_move_to(cairo, x + rounding, rounding);
|
||||
cairo_arc(cairo, x + rounding, rounding, rounding, -180.0 * (M_PI / 180.0), -90.0 * (M_PI / 180.0));
|
||||
cairo_rectangle(cairo, x, rounding, rounding, bar_height - rounding * 2);
|
||||
cairo_move_to(cairo, x + rounding, bar_height - rounding);
|
||||
cairo_arc(cairo, x + rounding, bar_height - rounding, rounding, -270.0 * (M_PI / 180.0), -180.0 * (M_PI / 180.0));
|
||||
x += rounding;
|
||||
width -= rounding;
|
||||
}
|
||||
|
||||
cairo_rectangle(cairo, x, 0, width, bar_height);
|
||||
cairo_fill(cairo);
|
||||
|
||||
i++;
|
||||
}
|
||||
// draw
|
||||
cairo_fill(cairo);
|
||||
|
||||
auto data = cairo_image_surface_get_data(cairo_surface);
|
||||
this->texture.allocate();
|
||||
this->mask_texture.allocate();
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, this->texture.m_iTexID);
|
||||
glBindTexture(GL_TEXTURE_2D, this->mask_texture.m_iTexID);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
|
||||
|
@ -143,12 +188,12 @@ void Hy3TabBar::prepareTexture() {
|
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
|
||||
#endif
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bar_width, bar_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
|
||||
cairo_destroy(cairo);
|
||||
cairo_surface_destroy(cairo_surface);
|
||||
} else {
|
||||
glBindTexture(GL_TEXTURE_2D, this->texture.m_iTexID);
|
||||
glBindTexture(GL_TEXTURE_2D, this->mask_texture.m_iTexID);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,8 +205,9 @@ Hy3TabGroup::Hy3TabGroup(Hy3Node& node) {
|
|||
this->size.registerVar();
|
||||
|
||||
this->updateWithGroup(node);
|
||||
this->pos.warp(false);
|
||||
this->size.warp(false);
|
||||
this->bar.updateAnimations(true);
|
||||
this->pos.warp();
|
||||
this->size.warp();
|
||||
}
|
||||
|
||||
void Hy3TabGroup::updateWithGroup(Hy3Node& node) {
|
||||
|
@ -174,7 +220,7 @@ void Hy3TabGroup::updateWithGroup(Hy3Node& node) {
|
|||
if (this->pos.goalv() != tpos) this->pos = tpos;
|
||||
if (this->size.goalv() != tsize) this->size = tsize;
|
||||
|
||||
this->bar.updateWithGroupEntries(node);
|
||||
this->bar.updateNodeList(node.data.as_group.children);
|
||||
}
|
||||
|
||||
void Hy3TabGroup::renderTabBar() {
|
||||
|
@ -183,16 +229,16 @@ void Hy3TabGroup::renderTabBar() {
|
|||
auto scale = monitor->scale;
|
||||
|
||||
auto pos = this->pos.vec();
|
||||
pos.y += this->bar.vertical_pos.fl();
|
||||
auto size = this->size.vec();
|
||||
|
||||
auto scaled_pos = Vector2D(std::round(pos.x * scale), std::round(pos.y * scale));
|
||||
auto scaled_size = Vector2D(std::round(size.x * scale), std::round(size.y * scale));
|
||||
auto box = wlr_box { scaled_pos.x, scaled_pos.y, scaled_size.x, scaled_size.y };
|
||||
|
||||
this->bar.setPos(scaled_pos);
|
||||
this->bar.setSize(scaled_size);
|
||||
|
||||
this->bar.prepareTexture();
|
||||
g_pHyprOpenGL->renderTexture(this->bar.texture, &box, 1.0);
|
||||
this->bar.prepareMask();
|
||||
g_pHyprOpenGL->renderTexture(this->bar.mask_texture, &box, this->bar.fade_opacity.fl());
|
||||
g_pHyprRenderer->damageBox(&box);
|
||||
}
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
|
||||
#include <hyprland/src/helpers/AnimatedVariable.hpp>
|
||||
#include <hyprland/src/helpers/Vector2D.hpp>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
class Hy3TabGroup;
|
||||
class Hy3TabBar;
|
||||
|
||||
#include "Hy3Layout.hpp"
|
||||
#include <hyprland/src/render/Texture.hpp>
|
||||
|
@ -12,25 +13,41 @@ class Hy3TabGroup;
|
|||
struct Hy3TabBarEntry {
|
||||
std::string window_title;
|
||||
bool urgent = false;
|
||||
bool focused = false;
|
||||
CAnimatedVariable offset; // offset 0, 0.0-1.0 of total bar
|
||||
CAnimatedVariable width; // 0.0-1.0 of total bar
|
||||
Hy3TabBar& tab_bar;
|
||||
Hy3Node& node; // only used for comparioson. do not deref.
|
||||
|
||||
Hy3TabBarEntry(Hy3TabBar&, Hy3Node&);
|
||||
bool operator==(const Hy3Node& node) const;
|
||||
};
|
||||
|
||||
class Hy3TabBar {
|
||||
public:
|
||||
CTexture texture;
|
||||
CTexture mask_texture;
|
||||
CAnimatedVariable vertical_pos;
|
||||
CAnimatedVariable fade_opacity;
|
||||
|
||||
void updateWithGroupEntries(Hy3Node&);
|
||||
void setPos(Vector2D);
|
||||
Hy3TabBar();
|
||||
|
||||
void focusNode(Hy3Node*);
|
||||
void updateNodeList(std::list<Hy3Node*>& nodes);
|
||||
void updateAnimations(bool warp = false);
|
||||
void setSize(Vector2D);
|
||||
|
||||
// Redraw the texture if necessary, and bind it to GL_TEXTURE_2D
|
||||
void prepareTexture();
|
||||
private:
|
||||
bool needs_redraw = true;
|
||||
// Redraw the mask texture if necessary, and bind it to GL_TEXTURE_2D
|
||||
void prepareMask();
|
||||
|
||||
std::vector<Hy3TabBarEntry> entries;
|
||||
// scaled pos/size
|
||||
Vector2D pos;
|
||||
private:
|
||||
bool need_mask_redraw = false;
|
||||
int last_mask_rounding = 0;
|
||||
|
||||
Hy3Node* focused_node = nullptr;
|
||||
CAnimatedVariable focus_opacity;
|
||||
CAnimatedVariable focus_start;
|
||||
CAnimatedVariable focus_end;
|
||||
|
||||
std::list<Hy3TabBarEntry> entries;
|
||||
Vector2D size;
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue