From f3e8d2ff9af7cb9c834abcfee598c14d18e13929 Mon Sep 17 00:00:00 2001 From: Pete Appleton Date: Sat, 27 Jan 2024 11:49:46 +0000 Subject: [PATCH] Fix resize breakage with expanded nodes --- src/Hy3Layout.cpp | 108 ++++++------------------------------- src/Hy3Layout.hpp | 6 +++ src/Hy3Node.cpp | 134 ++++++++++++++++++++++++++++++++++++---------- src/Hy3Node.hpp | 4 +- 4 files changed, 131 insertions(+), 121 deletions(-) diff --git a/src/Hy3Layout.cpp b/src/Hy3Layout.cpp index 369aa9f..91865ca 100644 --- a/src/Hy3Layout.cpp +++ b/src/Hy3Layout.cpp @@ -395,9 +395,9 @@ void Hy3Layout::resizeActiveWindow(const Vector2D& delta, eRectCorner corner, CW if (!g_pCompositor->windowValidMapped(window)) return; auto* node = this->getNodeFromWindow(window); + if(node != nullptr) { - if (node->parent != nullptr && node->parent->data.as_group.focused_child == node) - node = &node->getExpandActor(); + node = &node->getExpandActor(); auto monitor = g_pCompositor->getMonitorFromID(window->m_iMonitorID); @@ -423,44 +423,26 @@ void Hy3Layout::resizeActiveWindow(const Vector2D& delta, eRectCorner corner, CW // Determine the direction in which we're going to look for the sibling node // that will be resized - if(corner == CORNER_NONE) { // It's probably a keyboard event - // If the horizontal delta is negative & there's space available to the left, - // or if the horizontal delta is positive but space ISN'T available to the right - // then resize against the left-hand sibling. - // Otherwise, resize against the right-hand sibling - target_edge_x = (delta.x < 0 && display_left) || (delta.x > 0 && !display_right) + if(corner == CORNER_NONE) { // It's probably a keyboard event. + target_edge_x = display_right ? ShiftDirection::Left : ShiftDirection::Right; + target_edge_y = display_bottom ? ShiftDirection::Up : ShiftDirection::Down; + } else { // It's probably a mouse event + // Resize against the edges corresponding to the selected corner + target_edge_x = corner == CORNER_TOPLEFT || corner == CORNER_BOTTOMLEFT ? ShiftDirection::Left : ShiftDirection::Right; - - // If the vertical delta is negative & there's space available above it, - // or if the vertical delta is positive but space ISN'T available below - // then resize against the upper sibling. - // Otherwise, resize against the lower sibling - target_edge_y = (delta.y < 0 && display_top) || (delta.y >0 && !display_bottom) - ? ShiftDirection::Up : ShiftDirection::Down; - } else { // It's probaly a mouse event - // If the event was triggered from the right-hand side then resize - // against the previous [left] sibling - otherwise, resize against - // the next [right] sibling - target_edge_x = corner == CORNER_TOPRIGHT || corner == CORNER_BOTTOMRIGHT - ? ShiftDirection::Left : ShiftDirection::Right; - - // If the event was triggered from the bottom edge then resize - // against the previous [upper] sibling - otherwise, resize against - // the next [lower] sibling - target_edge_y = corner == CORNER_BOTTOMLEFT || corner == CORNER_BOTTOMRIGHT + target_edge_y = corner == CORNER_TOPLEFT || corner == CORNER_TOPRIGHT ? ShiftDirection::Up : ShiftDirection::Down; } - node = node->findSibling(node->data.as_group.layout, target_edge_x, target_edge_y); - auto* parent_node = node->parent; + auto sibling_node_x = node->findSibling(target_edge_x); + auto sibling_node_y = node->findSibling(target_edge_y); - if (parent_node != nullptr) { - resizeNode(node, resize_delta, target_edge_x, target_edge_y); + if(sibling_node_x) { + sibling_node_x->resize(resize_delta.x, target_edge_x); + } - auto* outer_node = node->findSibling(parent_node->data.as_group.layout, target_edge_x, target_edge_y); - if (outer_node != nullptr && outer_node->parent != nullptr) { - resizeNode(outer_node, resize_delta, target_edge_x, target_edge_y); - } + if(sibling_node_y) { + sibling_node_y->resize(resize_delta.y, target_edge_y); } } else { // No parent node - is this a floating window? If so, use the same logic as the `main` layout @@ -474,64 +456,6 @@ void Hy3Layout::resizeActiveWindow(const Vector2D& delta, eRectCorner corner, CW } } -void Hy3Layout::resizeNode( - Hy3Node* node, - Vector2D resize_delta, - ShiftDirection target_edge_x, - ShiftDirection target_edge_y -) { - auto& parent_node = node->parent; - auto& containing_group = parent_node->data.as_group; - const auto animate = - &g_pConfigManager->getConfigValuePtr("misc:animate_manual_resizes")->intValue; - - switch (containing_group.layout) { - case Hy3GroupLayout::SplitH: { - auto ratio_mod = - resize_delta.x * (float) containing_group.children.size() / parent_node->size.x; - - auto iter = std::find(containing_group.children.begin(), containing_group.children.end(), node); - - if (target_edge_x == ShiftDirection::Left) { - if (node == containing_group.children.back()) break; - iter = std::next(iter); - } else { - if (node == containing_group.children.front()) break; - iter = std::prev(iter); - ratio_mod = -ratio_mod; - } - - auto* neighbor = *iter; - - node->size_ratio += ratio_mod; - neighbor->size_ratio -= ratio_mod; - } break; - case Hy3GroupLayout::SplitV: { - auto ratio_mod = - resize_delta.y * (float) containing_group.children.size() / parent_node->size.y; - - auto iter = std::find(containing_group.children.begin(), containing_group.children.end(), node); - - if (target_edge_y == ShiftDirection::Up) { - if (node == containing_group.children.back()) break; - iter = std::next(iter); - } else { - if (node == containing_group.children.front()) break; - iter = std::prev(iter); - ratio_mod = -ratio_mod; - } - - auto* neighbor = *iter; - - node->size_ratio += ratio_mod; - neighbor->size_ratio -= ratio_mod; - } break; - case Hy3GroupLayout::Tabbed: break; - } - - parent_node->recalcSizePosRecursive(*animate == 0); -} - void Hy3Layout::fullscreenRequestForWindow( CWindow* window, eFullscreenMode fullscreen_mode, diff --git a/src/Hy3Layout.hpp b/src/Hy3Layout.hpp index 29f4e2a..f912849 100644 --- a/src/Hy3Layout.hpp +++ b/src/Hy3Layout.hpp @@ -20,6 +20,12 @@ enum class ShiftDirection { Right, }; +enum class Axis { + None, + Horizontal, + Vertical +}; + #include "Hy3Node.hpp" #include "TabGroup.hpp" diff --git a/src/Hy3Node.cpp b/src/Hy3Node.cpp index 4640d37..f44ae78 100644 --- a/src/Hy3Node.cpp +++ b/src/Hy3Node.cpp @@ -7,6 +7,8 @@ #include "Hy3Node.hpp" #include "globals.hpp" +const float MIN_RATIO = 0.02f; + // Hy3GroupData // Hy3GroupData::Hy3GroupData(Hy3GroupLayout layout): layout(layout) { @@ -812,52 +814,128 @@ Hy3Node* getOuterChild(Hy3GroupData &group, ShiftDirection direction) { switch (direction) { case ShiftDirection::Left: case ShiftDirection::Up: - return group.children.back(); + return group.children.front(); break; case ShiftDirection::Right: case ShiftDirection::Down: - return group.children.front(); + return group.children.back(); break; default: return nullptr; } } -Hy3Node* Hy3Node::findSibling(Hy3GroupLayout inner_layout, ShiftDirection direction_x, ShiftDirection direction_y) { - // break into parent groups when encountering a corner we're dragging in, a - // tab group, or a layout matching the inner_parent. +Hy3Node* Hy3Node::getImmediateSibling(ShiftDirection direction) { + const auto& group = this->parent->data.as_group; + auto iter = std::find(group.children.begin(), group.children.end(), this); + + std::__cxx11::list::const_iterator list_sibling; + + switch (direction) { + case ShiftDirection::Left: + case ShiftDirection::Up: + list_sibling = std::prev(iter); + break; + case ShiftDirection::Right: + case ShiftDirection::Down: + list_sibling = std::next(iter); + break; + default: + list_sibling = iter; + } + + if(list_sibling == group.children.end()) { + hy3_log(WARN, "getImmediateSibling: sibling not found"); + list_sibling = iter; + } + + return *list_sibling; +} + +Axis getAxis(Hy3GroupLayout layout) { + switch (layout) + { + case Hy3GroupLayout::SplitH: + return Axis::Horizontal; + case Hy3GroupLayout::SplitV: + return Axis::Vertical; + default: + return Axis::None; + } +} + +Axis getAxis(ShiftDirection direction) { + switch (direction) + { + case ShiftDirection::Left: + case ShiftDirection::Right: + return Axis::Horizontal; + case ShiftDirection::Down: + case ShiftDirection::Up: + return Axis::Vertical; + default: + return Axis::None; + } +} + +Hy3Node* Hy3Node::findSibling(ShiftDirection direction) { auto current_node = this; - while (current_node->parent != nullptr) { + Hy3Node* sibling = nullptr; + + while (sibling == nullptr && current_node->parent != nullptr) { auto& parent_group = current_node->parent->data.as_group; - // break out of all layouts that match the orientation of the inner_parent - if (parent_group.layout == inner_layout) { - goto cont2; + if(parent_group.layout != Hy3GroupLayout::Tabbed && getAxis(parent_group.layout) == getAxis(direction)) { + // If the current node is the outermost child of its parent group then proceed + // then we need to look at the parent - otherwise, the sibling is simply the immediate + // sibling in the child collection + if(getOuterChild(parent_group, direction) != current_node) { + sibling = current_node->getImmediateSibling(direction); + } } - switch (parent_group.layout) { - case Hy3GroupLayout::Tabbed: - // treat tabbed layouts as if they dont exist during resizing - goto cont2; - case Hy3GroupLayout::SplitH: - if(getOuterChild(parent_group, direction_x) == current_node) { - goto cont2; - } - break; - case Hy3GroupLayout::SplitV: - if(getOuterChild(parent_group, direction_y) == current_node) { - goto cont2; - } - break; - } - - break; - cont2: current_node = current_node->parent; } - return current_node; + return sibling; +} + +void Hy3Node::resize( + double resize_delta, + ShiftDirection target_edge_x +) { + auto& parent_node = this->parent; + auto& containing_group = parent_node->data.as_group; + const auto animate = + &g_pConfigManager->getConfigValuePtr("misc:animate_manual_resizes")->intValue; + + if(containing_group.layout != Hy3GroupLayout::Tabbed && getAxis(target_edge_x) == getAxis(containing_group.layout)) { + double parent_size = getAxis(target_edge_x) == Axis::Horizontal ? parent_node->size.x + : parent_node->size.y; + auto ratio_mod = resize_delta * (float) containing_group.children.size() / parent_size; + + auto iter = std::find(containing_group.children.begin(), containing_group.children.end(), this); + + if (target_edge_x == ShiftDirection::Left || target_edge_x == ShiftDirection::Up) { + if (this != containing_group.children.back()) { + iter = std::next(iter); + } + } else { + if (this != containing_group.children.front()) { + iter = std::prev(iter); + ratio_mod = -ratio_mod; + } + } + + auto* neighbor = *iter; + + if(this->size_ratio + ratio_mod > MIN_RATIO && neighbor->size_ratio - ratio_mod > MIN_RATIO) { + this->size_ratio += ratio_mod; + neighbor->size_ratio -= ratio_mod; + parent_node->recalcSizePosRecursive(*animate == 0); + } + } } void Hy3Node::swapData(Hy3Node& a, Hy3Node& b) { diff --git a/src/Hy3Node.hpp b/src/Hy3Node.hpp index 77ed7e9..148cc47 100644 --- a/src/Hy3Node.hpp +++ b/src/Hy3Node.hpp @@ -99,7 +99,9 @@ struct Hy3Node { void markFocused(); void raiseToTop(); Hy3Node* getFocusedNode(bool ignore_group_focus = false, bool stop_at_expanded = false); - Hy3Node* findSibling(Hy3GroupLayout inner_layout, ShiftDirection direction_x, ShiftDirection direction_y); + Hy3Node* findSibling(ShiftDirection); + Hy3Node* getImmediateSibling(ShiftDirection); + void resize(double, ShiftDirection); bool isIndirectlyFocused(); Hy3Node& getExpandActor();