From 8715516d93ec5164a091454b846a158e345da65c Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Sun, 28 May 2023 17:50:22 -0700 Subject: [PATCH] Tab removal animation Requires Hyprland#2389 (tracked in flake) --- flake.lock | 11 ++++--- flake.nix | 3 +- src/Hy3Layout.cpp | 2 +- src/Hy3Layout.hpp | 2 +- src/TabGroup.cpp | 77 ++++++++++++++++++++++++++++++++++------------- src/TabGroup.hpp | 18 ++++++++--- 6 files changed, 79 insertions(+), 34 deletions(-) diff --git a/flake.lock b/flake.lock index a52171d..b740f6a 100644 --- a/flake.lock +++ b/flake.lock @@ -8,16 +8,17 @@ "xdph": "xdph" }, "locked": { - "lastModified": 1685105343, - "narHash": "sha256-ypXKGzTQWJqbHHrPnSHLo4b2vNtfOFyh6sDdNPi7/WQ=", - "owner": "hyprwm", + "lastModified": 1685317265, + "narHash": "sha256-Bv/ksFWpm2RSRCY40pIJddNEn5G3yjLs9NUHbpVDGy0=", + "owner": "outfoxxed", "repo": "Hyprland", - "rev": "5f4659afef5856c509d53957e62b7f6c38d39f41", + "rev": "51441d5b9de13335e5723cdbb78e372ebe36490e", "type": "github" }, "original": { - "owner": "hyprwm", + "owner": "outfoxxed", "repo": "Hyprland", + "rev": "51441d5b9de13335e5723cdbb78e372ebe36490e", "type": "github" } }, diff --git a/flake.nix b/flake.nix index af84a45..3f70a66 100644 --- a/flake.nix +++ b/flake.nix @@ -1,6 +1,7 @@ { inputs = { - hyprland.url = "github:hyprwm/Hyprland"; + #hyprland.url = "github:hyprwm/Hyprland"; + hyprland.url = "github:outfoxxed/Hyprland?rev=51441d5b9de13335e5723cdbb78e372ebe36490e"; }; outputs = { self, hyprland, ... }: let diff --git a/src/Hy3Layout.cpp b/src/Hy3Layout.cpp index 38f828a..e97898e 100644 --- a/src/Hy3Layout.cpp +++ b/src/Hy3Layout.cpp @@ -1523,7 +1523,7 @@ void renderTabs(Hy3Node& node) { auto& group = node.data.as_group; if (!group.tab_bar) { - group.tab_bar = std::unique_ptr(new Hy3TabGroup(node)); + group.tab_bar = Hy3TabGroup::new_(node); } else { group.tab_bar->updateWithGroup(node); } diff --git a/src/Hy3Layout.hpp b/src/Hy3Layout.hpp index f4377a8..1dc286c 100644 --- a/src/Hy3Layout.hpp +++ b/src/Hy3Layout.hpp @@ -27,7 +27,7 @@ struct Hy3GroupData { std::list children; bool group_focused = true; Hy3Node* focused_child = nullptr; - std::unique_ptr tab_bar; + std::shared_ptr tab_bar; bool hasChild(Hy3Node* child); diff --git a/src/TabGroup.cpp b/src/TabGroup.cpp index 81fcfbb..ce664f4 100644 --- a/src/TabGroup.cpp +++ b/src/TabGroup.cpp @@ -5,7 +5,7 @@ #include #include -Hy3TabBarEntry::Hy3TabBarEntry(Hy3TabBar& tab_bar, Hy3Node& node): tab_bar(tab_bar), node(node) { +Hy3TabBarEntry::Hy3TabBarEntry(std::shared_ptr 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->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; } +bool Hy3TabBarEntry::operator==(const Hy3TabBarEntry& entry) const { + return this->node == entry.node; +} + void Hy3TabBarEntry::prepareTexture(float scale, Vector2D size) { 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() { 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& nodes) { - std::list removed_entries; + std::list::iterator> removed_entries; auto entry = this->entries.begin(); auto node = nodes.begin(); @@ -133,7 +147,8 @@ void Hy3TabBar::updateNodeList(std::list& nodes) { while (true) { if (entry == this->entries.end()) goto exitloop; 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); @@ -143,7 +158,10 @@ void Hy3TabBar::updateNodeList(std::list& nodes) { exitloop: // 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(); node = nodes.begin(); @@ -151,13 +169,24 @@ void Hy3TabBar::updateNodeList(std::list& nodes) { // 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(entry, removed_entries, moved); - entry = moved; - } else { - entry = this->entries.emplace(entry, *this, **node); + if (std::find(removed_entries.begin(), removed_entries.end(), entry) != removed_entries.end()) { + entry = std::next(entry); + continue; } + + 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 @@ -173,8 +202,7 @@ void Hy3TabBar::updateNodeList(std::list& nodes) { // initiate remove animations for any removed entries for (auto& entry: removed_entries) { - // TODO: working entry remove anim - entry.width = 0.0; + entry->animateRemoval(); } } @@ -210,10 +238,10 @@ void Hy3TabBar::updateAnimations(bool warp) { } 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); } } @@ -223,17 +251,24 @@ void Hy3TabBar::setSize(Vector2D size) { this->size = size; } -Hy3TabGroup::Hy3TabGroup(Hy3Node& node) { +Hy3TabGroup::Hy3TabGroup() { this->pos.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->size.registerVar(); +} - this->updateWithGroup(node); - this->bar.updateAnimations(true); - this->pos.warp(); - this->size.warp(); +std::shared_ptr Hy3TabGroup::new_(Hy3Node& node) { + auto ptr = std::shared_ptr(new Hy3TabGroup()); + ptr->self = ptr; + ptr->bar.group = ptr; + + ptr->updateWithGroup(node); + ptr->bar.updateAnimations(true); + ptr->pos.warp(); + ptr->size.warp(); + + return ptr; } void Hy3TabGroup::updateWithGroup(Hy3Node& node) { @@ -291,7 +326,7 @@ void Hy3TabGroup::renderTabBar() { wlr_box window_box = { wpos.x, wpos.y, wsize.x, wsize.y }; 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); diff --git a/src/TabGroup.hpp b/src/TabGroup.hpp index 2930999..7fa4ebd 100644 --- a/src/TabGroup.hpp +++ b/src/TabGroup.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include class Hy3TabGroup; @@ -19,16 +20,19 @@ struct Hy3TabBarEntry { CTexture texture; CAnimatedVariable offset; // offset 0, 0.0-1.0 of total bar CAnimatedVariable width; // 0.0-1.0 of total bar - Hy3TabBar& tab_bar; + std::shared_ptr tab_group; Hy3Node& node; // only used for comparioson. do not deref. Vector2D last_render_size; float last_render_scale = 0.0; float last_render_rounding = 0.0; - Hy3TabBarEntry(Hy3TabBar&, Hy3Node&); - bool operator==(const Hy3Node& node) const; + Hy3TabBarEntry(std::shared_ptr, Hy3Node&); + bool operator==(const Hy3Node&) const; + bool operator==(const Hy3TabBarEntry&) const; - void prepareTexture(float scale, Vector2D size); + void prepareTexture(float, Vector2D); + + void animateRemoval(); }; class Hy3TabBar { @@ -44,6 +48,7 @@ public: void setSize(Vector2D); std::list entries; + std::weak_ptr group; private: Hy3Node* focused_node = nullptr; CAnimatedVariable focus_opacity; @@ -60,7 +65,7 @@ public: CAnimatedVariable size; // initialize a group with the given node. UB if node is not a group. - Hy3TabGroup(Hy3Node&); + static std::shared_ptr new_(Hy3Node&); // update tab bar with node position and data. UB if node is not a group. void updateWithGroup(Hy3Node&); @@ -68,8 +73,11 @@ public: void renderTabBar(); private: + std::weak_ptr self; std::vector stencil_windows; + Hy3TabGroup(); + // moving a Hy3TabGroup will unregister any active animations Hy3TabGroup(Hy3TabGroup&&) = delete;