Fix resize breakage with expanded nodes

This commit is contained in:
Pete Appleton 2024-01-27 11:49:46 +00:00
parent 5820adc5c1
commit f3e8d2ff9a
4 changed files with 131 additions and 121 deletions

View file

@ -395,8 +395,8 @@ 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();
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);
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_x) {
sibling_node_x->resize(resize_delta.x, target_edge_x);
}
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,

View file

@ -20,6 +20,12 @@ enum class ShiftDirection {
Right,
};
enum class Axis {
None,
Horizontal,
Vertical
};
#include "Hy3Node.hpp"
#include "TabGroup.hpp"

View file

@ -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<Hy3Node *>::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) {

View file

@ -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();