diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index d1f219156..164741b5c 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -130,14 +130,15 @@ void CConfigManager::setDefaultVars() { configValues["decoration:dim_around"].floatValue = 0.4f; configValues["decoration:screen_shader"].strValue = STRVAL_EMPTY; - configValues["dwindle:pseudotile"].intValue = 0; - configValues["dwindle:force_split"].intValue = 0; - configValues["dwindle:preserve_split"].intValue = 0; - configValues["dwindle:special_scale_factor"].floatValue = 0.8f; - configValues["dwindle:split_width_multiplier"].floatValue = 1.0f; - configValues["dwindle:no_gaps_when_only"].intValue = 0; - configValues["dwindle:use_active_for_splits"].intValue = 1; - configValues["dwindle:default_split_ratio"].floatValue = 1.f; + configValues["dwindle:pseudotile"].intValue = 0; + configValues["dwindle:force_split"].intValue = 0; + configValues["dwindle:permanent_direction_override"].intValue = 0; + configValues["dwindle:preserve_split"].intValue = 0; + configValues["dwindle:special_scale_factor"].floatValue = 0.8f; + configValues["dwindle:split_width_multiplier"].floatValue = 1.0f; + configValues["dwindle:no_gaps_when_only"].intValue = 0; + configValues["dwindle:use_active_for_splits"].intValue = 1; + configValues["dwindle:default_split_ratio"].floatValue = 1.f; configValues["master:special_scale_factor"].floatValue = 0.8f; configValues["master:mfact"].floatValue = 0.55f; diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index bda646805..a1b7d6d78 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -1,7 +1,7 @@ #include "DwindleLayout.hpp" #include "../Compositor.hpp" -void SDwindleNodeData::recalcSizePosRecursive(bool force) { +void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverride, bool verticalOverride) { if (children[0]) { const auto REVERSESPLITRATIO = 2.f - splitRatio; @@ -13,6 +13,11 @@ void SDwindleNodeData::recalcSizePosRecursive(bool force) { splitTop = size.y * *PFLMULT > size.x; } + if (verticalOverride == true) + splitTop = true; + else if (horizontalOverride == true) + splitTop = false; + const auto SPLITSIDE = !splitTop; if (SPLITSIDE) { @@ -334,11 +339,37 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) { const auto SIDEBYSIDE = NEWPARENT->size.x > NEWPARENT->size.y * *PWIDTHMULTIPLIER; NEWPARENT->splitTop = !SIDEBYSIDE; - const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal(); + const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal(); - const auto PFORCESPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:force_split")->intValue; + static auto* const PFORCESPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:force_split")->intValue; + static auto* const PERMANENTDIRECTIONOVERRIDE = &g_pConfigManager->getConfigValuePtr("dwindle:permanent_direction_override")->intValue; - if (*PFORCESPLIT == 0) { + bool horizontalOverride = false; + bool verticalOverride = false; + + // let user select position -> top, right, bottom, left + if (overrideDirection != OneTimeFocus::NOFOCUS) { + + // this is horizontal + if (overrideDirection % 2 == 0) + verticalOverride = true; + else + horizontalOverride = true; + + // 0 -> top and left | 1,2 -> right and bottom + if (overrideDirection % 3 == 0) { + NEWPARENT->children[1] = OPENINGON; + NEWPARENT->children[0] = PNODE; + } else { + NEWPARENT->children[0] = OPENINGON; + NEWPARENT->children[1] = PNODE; + } + + // whether or not the override persists after opening one window + if (*PERMANENTDIRECTIONOVERRIDE == 0) + overrideDirection = OneTimeFocus::NOFOCUS; + + } else if (*PFORCESPLIT == 0) { if ((SIDEBYSIDE && VECINRECT(MOUSECOORDS, NEWPARENT->position.x, NEWPARENT->position.y / *PWIDTHMULTIPLIER, NEWPARENT->position.x + NEWPARENT->size.x / 2.f, NEWPARENT->position.y + NEWPARENT->size.y)) || @@ -373,9 +404,8 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) { } // Update the children - - if (NEWPARENT->size.x * *PWIDTHMULTIPLIER > NEWPARENT->size.y) { - // split left/right + if (!verticalOverride && (NEWPARENT->size.x * *PWIDTHMULTIPLIER > NEWPARENT->size.y || horizontalOverride)) { + // split left/right -> forced OPENINGON->position = NEWPARENT->position; OPENINGON->size = Vector2D(NEWPARENT->size.x / 2.f, NEWPARENT->size.y); PNODE->position = Vector2D(NEWPARENT->position.x + NEWPARENT->size.x / 2.f, NEWPARENT->position.y); @@ -391,7 +421,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) { OPENINGON->pParent = NEWPARENT; PNODE->pParent = NEWPARENT; - NEWPARENT->recalcSizePosRecursive(); + NEWPARENT->recalcSizePosRecursive(false, horizontalOverride, verticalOverride); applyNodeDataToWindow(PNODE); applyNodeDataToWindow(OPENINGON); @@ -811,8 +841,44 @@ void CHyprDwindleLayout::alterSplitRatio(CWindow* pWindow, float ratio, bool exa } std::any CHyprDwindleLayout::layoutMessage(SLayoutMessageHeader header, std::string message) { - if (message == "togglesplit") + const auto ARGS = CVarList(message, 0, ' '); + if (ARGS[0] == "togglesplit") { toggleSplit(header.pWindow); + } else if (ARGS[0] == "preselect") { + std::string direction = ARGS[1]; + + if (direction.empty()) { + Debug::log(ERR, "Expected direction for preselect"); + return ""; + } + + switch (direction.front()) { + case 'u': + case 't': { + overrideDirection = OneTimeFocus::UP; + break; + } + case 'd': + case 'b': { + overrideDirection = OneTimeFocus::DOWN; + break; + } + case 'r': { + overrideDirection = OneTimeFocus::RIGHT; + break; + } + case 'l': { + overrideDirection = OneTimeFocus::LEFT; + break; + } + default: { + // any other character resets the focus direction + // needed for the persistent mode + overrideDirection = OneTimeFocus::NOFOCUS; + break; + } + } + } return ""; } diff --git a/src/layout/DwindleLayout.hpp b/src/layout/DwindleLayout.hpp index 164596a39..ed7ddf860 100644 --- a/src/layout/DwindleLayout.hpp +++ b/src/layout/DwindleLayout.hpp @@ -9,6 +9,14 @@ class CHyprDwindleLayout; enum eFullscreenMode : uint8_t; +enum OneTimeFocus { + UP = 0, + RIGHT, + DOWN, + LEFT, + NOFOCUS, +}; + struct SDwindleNodeData { SDwindleNodeData* pParent = nullptr; bool isNode = false; @@ -34,7 +42,7 @@ struct SDwindleNodeData { children[0] == rhs.children[0] && children[1] == rhs.children[1]; } - void recalcSizePosRecursive(bool force = false); + void recalcSizePosRecursive(bool force = false, bool horizontalOverride = false, bool verticalOverride = false); void getAllChildrenRecursive(std::deque*); CHyprDwindleLayout* layout = nullptr; }; @@ -77,5 +85,7 @@ class CHyprDwindleLayout : public IHyprLayout { void toggleSplit(CWindow*); + OneTimeFocus overrideDirection = OneTimeFocus::NOFOCUS; + friend struct SDwindleNodeData; };