From dad1589d2185d32243f8089a67ad2637d6233eae Mon Sep 17 00:00:00 2001 From: Pete Appleton Date: Mon, 29 Jan 2024 08:31:16 +0000 Subject: [PATCH] Improve iteration handling and validate results --- src/Hy3Layout.cpp | 52 +++++++++++++++++++++++++----------- src/Hy3Node.cpp | 67 +++++++++++++++++++++++++++++------------------ src/Hy3Node.hpp | 4 +-- 3 files changed, 81 insertions(+), 42 deletions(-) diff --git a/src/Hy3Layout.cpp b/src/Hy3Layout.cpp index 91865ca..c62b306 100644 --- a/src/Hy3Layout.cpp +++ b/src/Hy3Layout.cpp @@ -390,6 +390,17 @@ void Hy3Layout::recalculateWindow(CWindow* window) { node->recalcSizePosRecursive(); } +ShiftDirection reverse(ShiftDirection direction) { + switch (direction) + { + case ShiftDirection::Left: return ShiftDirection::Right; + case ShiftDirection::Right: return ShiftDirection::Left; + case ShiftDirection::Up: return ShiftDirection::Down; + case ShiftDirection::Down: return ShiftDirection::Up; + default: return direction; + } +} + void Hy3Layout::resizeActiveWindow(const Vector2D& delta, eRectCorner corner, CWindow* pWindow) { auto window = pWindow ? pWindow : g_pCompositor->m_pLastWindow; if (!g_pCompositor->windowValidMapped(window)) return; @@ -421,11 +432,15 @@ void Hy3Layout::resizeActiveWindow(const Vector2D& delta, eRectCorner corner, CW ShiftDirection target_edge_x; ShiftDirection target_edge_y; - // Determine the direction in which we're going to look for the sibling node + // Determine the direction in which we're going to look for the neighbor node // that will be resized 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; + + // If the anchor is not at the top/left then reverse the delta + if(target_edge_x == ShiftDirection::Left) resize_delta.x = -resize_delta.x; + if(target_edge_y == ShiftDirection::Up) resize_delta.y = -resize_delta.y; } 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 @@ -434,25 +449,32 @@ void Hy3Layout::resizeActiveWindow(const Vector2D& delta, eRectCorner corner, CW ? ShiftDirection::Up : ShiftDirection::Down; } - auto sibling_node_x = node->findSibling(target_edge_x); - auto sibling_node_y = node->findSibling(target_edge_y); + // Find the neighboring node in each axis, which will be either above or at the + // same level as the initiating node in the layout hierarchy. These are the nodes + // which must get resized (rather than the initiator) because they are the + // highest point in the hierarchy + auto horizontal_neighbor = node->findNeighbor(target_edge_x); + auto vertical_neighbor = node->findNeighbor(target_edge_y); - if(sibling_node_x) { - sibling_node_x->resize(resize_delta.x, target_edge_x); + const auto animate = + &g_pConfigManager->getConfigValuePtr("misc:animate_manual_resizes")->intValue; + + // Note that the resize direction is reversed, because from the neighbor's perspective + // the edge to be moved is the opposite way round. However, the delta is still the same. + if(horizontal_neighbor) { + horizontal_neighbor->resize(reverse(target_edge_x), resize_delta.x, *animate == 0); } - if(sibling_node_y) { - sibling_node_y->resize(resize_delta.y, target_edge_y); + if(vertical_neighbor) { + vertical_neighbor->resize(reverse(target_edge_y), resize_delta.y, *animate == 0); } - } else { + } else if(window->m_bIsFloating) { // No parent node - is this a floating window? If so, use the same logic as the `main` layout - if(window->m_bIsFloating) { - const auto required_size = Vector2D( - std::max((window->m_vRealSize.goalv() + delta).x, 20.0), - std::max((window->m_vRealSize.goalv() + delta).y, 20.0) - ); - window->m_vRealSize = required_size; - } + const auto required_size = Vector2D( + std::max((window->m_vRealSize.goalv() + delta).x, 20.0), + std::max((window->m_vRealSize.goalv() + delta).y, 20.0) + ); + window->m_vRealSize = required_size; } } diff --git a/src/Hy3Node.cpp b/src/Hy3Node.cpp index f44ae78..6c2c415 100644 --- a/src/Hy3Node.cpp +++ b/src/Hy3Node.cpp @@ -7,7 +7,7 @@ #include "Hy3Node.hpp" #include "globals.hpp" -const float MIN_RATIO = 0.02f; +const float MIN_WINDOW_SIZE = 20; // Hy3GroupData // @@ -879,7 +879,7 @@ Axis getAxis(ShiftDirection direction) { } } -Hy3Node* Hy3Node::findSibling(ShiftDirection direction) { +Hy3Node* Hy3Node::findNeighbor(ShiftDirection direction) { auto current_node = this; Hy3Node* sibling = nullptr; @@ -901,40 +901,57 @@ Hy3Node* Hy3Node::findSibling(ShiftDirection direction) { return sibling; } +int directionToIteratorIncrement(ShiftDirection direction) { + switch (direction) + { + case ShiftDirection::Left: + case ShiftDirection::Up: + return -1; + case ShiftDirection::Right: + case ShiftDirection::Down: + return 1; + default: + hy3_log(WARN, "Unknown ShiftDirection enum value: {}", (int)direction); + return 1; + } +} + void Hy3Node::resize( - double resize_delta, - ShiftDirection target_edge_x + ShiftDirection direction, + double delta, + bool no_animation ) { 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 + if(containing_group.layout != Hy3GroupLayout::Tabbed && getAxis(direction) == getAxis(containing_group.layout)) { + double parent_size = getAxis(direction) == Axis::Horizontal ? parent_node->size.x : parent_node->size.y; - auto ratio_mod = resize_delta * (float) containing_group.children.size() / parent_size; + auto ratio_mod = delta * (float) containing_group.children.size() / parent_size; - auto iter = std::find(containing_group.children.begin(), containing_group.children.end(), this); + const auto end_of_children = containing_group.children.end(); + auto iter = std::find(containing_group.children.begin(), end_of_children, this); - if (target_edge_x == ShiftDirection::Left || target_edge_x == ShiftDirection::Up) { - if (this != containing_group.children.back()) { - iter = std::next(iter); + if(iter != end_of_children) { + const auto outermost_node_in_group = getOuterChild(containing_group, direction); + if(this != outermost_node_in_group) { + auto inc = directionToIteratorIncrement(direction); + iter = std::next(iter, inc); + ratio_mod *= inc; } - } else { - if (this != containing_group.children.front()) { - iter = std::prev(iter); - ratio_mod = -ratio_mod; + + if(iter != end_of_children) { + auto* neighbor = *iter; + auto requested_size_ratio = this->size_ratio + ratio_mod; + auto requested_neighbor_size_ratio = neighbor->size_ratio -ratio_mod; + + if(requested_size_ratio * parent_size >= MIN_WINDOW_SIZE) { + this->size_ratio = requested_size_ratio; + neighbor->size_ratio = requested_neighbor_size_ratio; + parent_node->recalcSizePosRecursive(no_animation); + } } } - - 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); - } } } diff --git a/src/Hy3Node.hpp b/src/Hy3Node.hpp index 148cc47..f892efb 100644 --- a/src/Hy3Node.hpp +++ b/src/Hy3Node.hpp @@ -99,9 +99,9 @@ struct Hy3Node { void markFocused(); void raiseToTop(); Hy3Node* getFocusedNode(bool ignore_group_focus = false, bool stop_at_expanded = false); - Hy3Node* findSibling(ShiftDirection); + Hy3Node* findNeighbor(ShiftDirection); Hy3Node* getImmediateSibling(ShiftDirection); - void resize(double, ShiftDirection); + void resize(ShiftDirection, double, bool no_animation = false); bool isIndirectlyFocused(); Hy3Node& getExpandActor();