Tab removal animation

Requires Hyprland#2389 (tracked in flake)
This commit is contained in:
outfoxxed 2023-05-28 17:50:22 -07:00
parent d78601b5c8
commit 8715516d93
No known key found for this signature in database
GPG key ID: 4C88A185FB89301E
6 changed files with 79 additions and 34 deletions

11
flake.lock generated
View file

@ -8,16 +8,17 @@
"xdph": "xdph" "xdph": "xdph"
}, },
"locked": { "locked": {
"lastModified": 1685105343, "lastModified": 1685317265,
"narHash": "sha256-ypXKGzTQWJqbHHrPnSHLo4b2vNtfOFyh6sDdNPi7/WQ=", "narHash": "sha256-Bv/ksFWpm2RSRCY40pIJddNEn5G3yjLs9NUHbpVDGy0=",
"owner": "hyprwm", "owner": "outfoxxed",
"repo": "Hyprland", "repo": "Hyprland",
"rev": "5f4659afef5856c509d53957e62b7f6c38d39f41", "rev": "51441d5b9de13335e5723cdbb78e372ebe36490e",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "hyprwm", "owner": "outfoxxed",
"repo": "Hyprland", "repo": "Hyprland",
"rev": "51441d5b9de13335e5723cdbb78e372ebe36490e",
"type": "github" "type": "github"
} }
}, },

View file

@ -1,6 +1,7 @@
{ {
inputs = { inputs = {
hyprland.url = "github:hyprwm/Hyprland"; #hyprland.url = "github:hyprwm/Hyprland";
hyprland.url = "github:outfoxxed/Hyprland?rev=51441d5b9de13335e5723cdbb78e372ebe36490e";
}; };
outputs = { self, hyprland, ... }: let outputs = { self, hyprland, ... }: let

View file

@ -1523,7 +1523,7 @@ void renderTabs(Hy3Node& node) {
auto& group = node.data.as_group; auto& group = node.data.as_group;
if (!group.tab_bar) { if (!group.tab_bar) {
group.tab_bar = std::unique_ptr<Hy3TabGroup>(new Hy3TabGroup(node)); group.tab_bar = Hy3TabGroup::new_(node);
} else { } else {
group.tab_bar->updateWithGroup(node); group.tab_bar->updateWithGroup(node);
} }

View file

@ -27,7 +27,7 @@ struct Hy3GroupData {
std::list<Hy3Node*> children; std::list<Hy3Node*> children;
bool group_focused = true; bool group_focused = true;
Hy3Node* focused_child = nullptr; Hy3Node* focused_child = nullptr;
std::unique_ptr<Hy3TabGroup> tab_bar; std::shared_ptr<Hy3TabGroup> tab_bar;
bool hasChild(Hy3Node* child); bool hasChild(Hy3Node* child);

View file

@ -5,7 +5,7 @@
#include <hyprland/src/Compositor.hpp> #include <hyprland/src/Compositor.hpp>
#include <cairo/cairo.h> #include <cairo/cairo.h>
Hy3TabBarEntry::Hy3TabBarEntry(Hy3TabBar& tab_bar, Hy3Node& node): tab_bar(tab_bar), node(node) { Hy3TabBarEntry::Hy3TabBarEntry(std::shared_ptr<Hy3TabGroup> tab_group, Hy3Node& node): tab_group(tab_group), node(node) {
this->offset.create(AVARTYPE_FLOAT, -1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), nullptr, AVARDAMAGE_NONE); this->offset.create(AVARTYPE_FLOAT, -1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), nullptr, AVARDAMAGE_NONE);
this->width.create(AVARTYPE_FLOAT, -1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), nullptr, AVARDAMAGE_NONE); this->width.create(AVARTYPE_FLOAT, -1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), nullptr, AVARDAMAGE_NONE);
@ -20,6 +20,10 @@ bool Hy3TabBarEntry::operator==(const Hy3Node& node) const {
return this->node == node; return this->node == node;
} }
bool Hy3TabBarEntry::operator==(const Hy3TabBarEntry& entry) const {
return this->node == entry.node;
}
void Hy3TabBarEntry::prepareTexture(float scale, Vector2D size) { void Hy3TabBarEntry::prepareTexture(float scale, Vector2D size) {
static const auto* rounding_setting = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:rounding")->intValue; static const auto* rounding_setting = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:rounding")->intValue;
@ -91,6 +95,16 @@ void Hy3TabBarEntry::prepareTexture(float scale, Vector2D size) {
} }
} }
void Hy3TabBarEntry::animateRemoval() {
if (this->width.goalf() == 0.0) return;
this->width = 0.0;
// not removing the callback is required for soundness, as the animation will
// be deleted once the callback ends.
this->width.setCallbackOnEnd([this](void*) {
this->tab_group->bar.entries.remove(*this);
}, false);
}
Hy3TabBar::Hy3TabBar() { Hy3TabBar::Hy3TabBar() {
this->vertical_pos.create(AVARTYPE_FLOAT, 1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), nullptr, AVARDAMAGE_NONE); this->vertical_pos.create(AVARTYPE_FLOAT, 1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), nullptr, AVARDAMAGE_NONE);
@ -123,7 +137,7 @@ void Hy3TabBar::focusNode(Hy3Node* node) {
} }
void Hy3TabBar::updateNodeList(std::list<Hy3Node*>& nodes) { void Hy3TabBar::updateNodeList(std::list<Hy3Node*>& nodes) {
std::list<Hy3TabBarEntry> removed_entries; std::list<std::list<Hy3TabBarEntry>::iterator> removed_entries;
auto entry = this->entries.begin(); auto entry = this->entries.begin();
auto node = nodes.begin(); auto node = nodes.begin();
@ -133,7 +147,8 @@ void Hy3TabBar::updateNodeList(std::list<Hy3Node*>& nodes) {
while (true) { while (true) {
if (entry == this->entries.end()) goto exitloop; if (entry == this->entries.end()) goto exitloop;
if (*entry == **node) break; if (*entry == **node) break;
removed_entries.splice(removed_entries.end(), this->entries, entry++); removed_entries.push_back(entry);
entry = std::next(entry);
} }
node = std::next(node); node = std::next(node);
@ -143,7 +158,10 @@ void Hy3TabBar::updateNodeList(std::list<Hy3Node*>& nodes) {
exitloop: exitloop:
// move any extra entries to removed_entries // move any extra entries to removed_entries
removed_entries.splice(removed_entries.end(), this->entries, entry, this->entries.end()); while (entry != this->entries.end()) {
removed_entries.push_back(entry);
entry = std::next(entry);
}
entry = this->entries.begin(); entry = this->entries.begin();
node = nodes.begin(); node = nodes.begin();
@ -151,13 +169,24 @@ void Hy3TabBar::updateNodeList(std::list<Hy3Node*>& nodes) {
// add missing entries, taking first from removed_entries // add missing entries, taking first from removed_entries
while (node != nodes.end()) { while (node != nodes.end()) {
if (entry == this->entries.end() || *entry != **node) { if (entry == this->entries.end() || *entry != **node) {
auto moved = std::find(removed_entries.begin(), removed_entries.end(), **node); if (std::find(removed_entries.begin(), removed_entries.end(), entry) != removed_entries.end()) {
if (moved != removed_entries.end()) { entry = std::next(entry);
this->entries.splice(entry, removed_entries, moved); continue;
entry = moved;
} else {
entry = this->entries.emplace(entry, *this, **node);
} }
auto moved = std::find_if(removed_entries.begin(), removed_entries.end(), [&node](auto entry) { return **node == *entry; });
if (moved != removed_entries.end()) {
this->entries.splice(entry, this->entries, *moved);
entry = *moved;
removed_entries.erase(moved);
} else {
entry = this->entries.emplace(entry, this->group.lock(), **node);
}
}
if (entry->width.goalf() == 0.0) {
entry->width.setCallbackOnEnd(nullptr);
entry->width = -1.0;
} }
// set stats from node data // set stats from node data
@ -173,8 +202,7 @@ void Hy3TabBar::updateNodeList(std::list<Hy3Node*>& nodes) {
// initiate remove animations for any removed entries // initiate remove animations for any removed entries
for (auto& entry: removed_entries) { for (auto& entry: removed_entries) {
// TODO: working entry remove anim entry->animateRemoval();
entry.width = 0.0;
} }
} }
@ -210,10 +238,10 @@ void Hy3TabBar::updateAnimations(bool warp) {
} }
if (entry->offset.goalf() != offset) entry->offset = offset; if (entry->offset.goalf() != offset) entry->offset = offset;
if (entry->width.goalf() != entry_width) entry->width = entry_width; if ((warp_init || entry->width.goalf() != 0.0) && entry->width.goalf() != entry_width) entry->width = entry_width;
} }
offset += entry_width; offset += entry->width.goalf();
entry = std::next(entry); entry = std::next(entry);
} }
} }
@ -223,17 +251,24 @@ void Hy3TabBar::setSize(Vector2D size) {
this->size = size; this->size = size;
} }
Hy3TabGroup::Hy3TabGroup(Hy3Node& node) { Hy3TabGroup::Hy3TabGroup() {
this->pos.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), nullptr, AVARDAMAGE_NONE); this->pos.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), nullptr, AVARDAMAGE_NONE);
this->size.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), nullptr, AVARDAMAGE_NONE); this->size.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), nullptr, AVARDAMAGE_NONE);
Debug::log(LOG, "registered anims");
this->pos.registerVar(); this->pos.registerVar();
this->size.registerVar(); this->size.registerVar();
}
this->updateWithGroup(node); std::shared_ptr<Hy3TabGroup> Hy3TabGroup::new_(Hy3Node& node) {
this->bar.updateAnimations(true); auto ptr = std::shared_ptr<Hy3TabGroup>(new Hy3TabGroup());
this->pos.warp(); ptr->self = ptr;
this->size.warp(); ptr->bar.group = ptr;
ptr->updateWithGroup(node);
ptr->bar.updateAnimations(true);
ptr->pos.warp();
ptr->size.warp();
return ptr;
} }
void Hy3TabGroup::updateWithGroup(Hy3Node& node) { void Hy3TabGroup::updateWithGroup(Hy3Node& node) {
@ -291,7 +326,7 @@ void Hy3TabGroup::renderTabBar() {
wlr_box window_box = { wpos.x, wpos.y, wsize.x, wsize.y }; wlr_box window_box = { wpos.x, wpos.y, wsize.x, wsize.y };
scaleBox(&window_box, scale); scaleBox(&window_box, scale);
g_pHyprOpenGL->renderRect(&window_box, CColor(0, 0, 0, 0), *window_rounding); if (window_box.width > 0 && window_box.height > 0) g_pHyprOpenGL->renderRect(&window_box, CColor(0, 0, 0, 0), *window_rounding);
} }
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

View file

@ -3,6 +3,7 @@
#include <hyprland/src/helpers/AnimatedVariable.hpp> #include <hyprland/src/helpers/AnimatedVariable.hpp>
#include <hyprland/src/helpers/Vector2D.hpp> #include <hyprland/src/helpers/Vector2D.hpp>
#include <list> #include <list>
#include <memory>
#include <vector> #include <vector>
class Hy3TabGroup; class Hy3TabGroup;
@ -19,16 +20,19 @@ struct Hy3TabBarEntry {
CTexture texture; CTexture texture;
CAnimatedVariable offset; // offset 0, 0.0-1.0 of total bar CAnimatedVariable offset; // offset 0, 0.0-1.0 of total bar
CAnimatedVariable width; // 0.0-1.0 of total bar CAnimatedVariable width; // 0.0-1.0 of total bar
Hy3TabBar& tab_bar; std::shared_ptr<Hy3TabGroup> tab_group;
Hy3Node& node; // only used for comparioson. do not deref. Hy3Node& node; // only used for comparioson. do not deref.
Vector2D last_render_size; Vector2D last_render_size;
float last_render_scale = 0.0; float last_render_scale = 0.0;
float last_render_rounding = 0.0; float last_render_rounding = 0.0;
Hy3TabBarEntry(Hy3TabBar&, Hy3Node&); Hy3TabBarEntry(std::shared_ptr<Hy3TabGroup>, Hy3Node&);
bool operator==(const Hy3Node& node) const; bool operator==(const Hy3Node&) const;
bool operator==(const Hy3TabBarEntry&) const;
void prepareTexture(float scale, Vector2D size); void prepareTexture(float, Vector2D);
void animateRemoval();
}; };
class Hy3TabBar { class Hy3TabBar {
@ -44,6 +48,7 @@ public:
void setSize(Vector2D); void setSize(Vector2D);
std::list<Hy3TabBarEntry> entries; std::list<Hy3TabBarEntry> entries;
std::weak_ptr<Hy3TabGroup> group;
private: private:
Hy3Node* focused_node = nullptr; Hy3Node* focused_node = nullptr;
CAnimatedVariable focus_opacity; CAnimatedVariable focus_opacity;
@ -60,7 +65,7 @@ public:
CAnimatedVariable size; CAnimatedVariable size;
// initialize a group with the given node. UB if node is not a group. // initialize a group with the given node. UB if node is not a group.
Hy3TabGroup(Hy3Node&); static std::shared_ptr<Hy3TabGroup> new_(Hy3Node&);
// update tab bar with node position and data. UB if node is not a group. // update tab bar with node position and data. UB if node is not a group.
void updateWithGroup(Hy3Node&); void updateWithGroup(Hy3Node&);
@ -68,8 +73,11 @@ public:
void renderTabBar(); void renderTabBar();
private: private:
std::weak_ptr<Hy3TabGroup> self;
std::vector<CWindow*> stencil_windows; std::vector<CWindow*> stencil_windows;
Hy3TabGroup();
// moving a Hy3TabGroup will unregister any active animations // moving a Hy3TabGroup will unregister any active animations
Hy3TabGroup(Hy3TabGroup&&) = delete; Hy3TabGroup(Hy3TabGroup&&) = delete;