Skip to content

Commit

Permalink
master: Add smart resizing option for master layout (#3210)
Browse files Browse the repository at this point in the history
* add smart resizing for master layout

* fix smart resizing workspace check

* master layout fix smart resize when at max size

* change resizing for center orientation so it doesnt use all nodes

* master layout resizing, simplify code for calculating total height and weight

* remove the redundant smart resizing check
  • Loading branch information
thejch committed Sep 10, 2023
1 parent 0d53401 commit 19bbdee
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 13 deletions.
1 change: 1 addition & 0 deletions src/config/ConfigManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ void CConfigManager::setDefaultVars() {
configValues["master:orientation"].strValue = "left";
configValues["master:inherit_fullscreen"].intValue = 1;
configValues["master:allow_small_split"].intValue = 0;
configValues["master:smart_resizing"].intValue = 1;

configValues["animations:enabled"].intValue = 1;

Expand Down
178 changes: 165 additions & 13 deletions src/layout/MasterLayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
eOrientation orientation = PWORKSPACEDATA->orientation;
bool centerMasterWindow = false;
static auto* const ALWAYSCENTER = &g_pConfigManager->getConfigValuePtr("master:always_center_master")->intValue;
static auto* const PSMARTRESIZING = &g_pConfigManager->getConfigValuePtr("master:smart_resizing")->intValue;

const auto MASTERS = getMastersOnWorkspace(PWORKSPACE->m_iID);
const auto WINDOWS = getNodesOnWorkspace(PWORKSPACE->m_iID);
Expand All @@ -293,6 +294,25 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
}
}

const float totalSize = (orientation == ORIENTATION_TOP || orientation == ORIENTATION_BOTTOM) ? WSSIZE.x : WSSIZE.y;
const float masterAverageSize = totalSize / MASTERS;
const float slaveAverageSize = totalSize / STACKWINDOWS;
float masterAccumulatedSize = 0;
float slaveAccumulatedSize = 0;

if (*PSMARTRESIZING) {
// check the total width and height so that later
// if larger/smaller than screen size them down/up
for (auto& nd : m_lMasterNodesData) {
if (nd.workspaceID == PWORKSPACE->m_iID) {
if (nd.isMaster)
masterAccumulatedSize += totalSize / MASTERS * nd.percSize;
else
slaveAccumulatedSize += totalSize / STACKWINDOWS * nd.percSize;
}
}
}

// compute placement of master window(s)
if (WINDOWS == 1 && !centerMasterWindow) {
PMASTERNODE->size = WSSIZE;
Expand All @@ -318,6 +338,11 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
if (WIDTH > widthLeft * 0.9f && mastersLeft > 1)
WIDTH = widthLeft * 0.9f;

if (*PSMARTRESIZING) {
nd.percSize *= WSSIZE.x / masterAccumulatedSize;
WIDTH = masterAverageSize * nd.percSize;
}

nd.size = Vector2D(WIDTH, HEIGHT);
nd.position = WSPOS + Vector2D(nextX, nextY);
applyNodeDataToWindow(&nd);
Expand Down Expand Up @@ -350,6 +375,11 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
if (HEIGHT > heightLeft * 0.9f && mastersLeft > 1)
HEIGHT = heightLeft * 0.9f;

if (*PSMARTRESIZING) {
nd.percSize *= WSSIZE.y / masterAccumulatedSize;
HEIGHT = masterAverageSize * nd.percSize;
}

nd.size = Vector2D(WIDTH, HEIGHT);
nd.position = WSPOS + Vector2D(nextX, nextY);
applyNodeDataToWindow(&nd);
Expand Down Expand Up @@ -382,6 +412,11 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
if (WIDTH > widthLeft * 0.9f && slavesLeft > 1)
WIDTH = widthLeft * 0.9f;

if (*PSMARTRESIZING) {
nd.percSize *= WSSIZE.x / slaveAccumulatedSize;
WIDTH = slaveAverageSize * nd.percSize;
}

nd.size = Vector2D(WIDTH, HEIGHT);
nd.position = WSPOS + Vector2D(nextX, nextY);
applyNodeDataToWindow(&nd);
Expand All @@ -407,6 +442,11 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
if (HEIGHT > heightLeft * 0.9f && slavesLeft > 1)
HEIGHT = heightLeft * 0.9f;

if (*PSMARTRESIZING) {
nd.percSize *= WSSIZE.y / slaveAccumulatedSize;
HEIGHT = slaveAverageSize * nd.percSize;
}

nd.size = Vector2D(WIDTH, HEIGHT);
nd.position = WSPOS + Vector2D(nextX, nextY);
applyNodeDataToWindow(&nd);
Expand All @@ -429,6 +469,25 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
int slavesLeftR = 1 + (slavesLeft - 1) / 2;
int slavesLeftL = slavesLeft - slavesLeftR;

const float slaveAverageHeightL = WSSIZE.y / slavesLeftL;
const float slaveAverageHeightR = WSSIZE.y / slavesLeftR;
float slaveAccumulatedHeightL = 0;
float slaveAccumulatedHeightR = 0;
if (*PSMARTRESIZING) {
for (auto& nd : m_lMasterNodesData) {
if (nd.workspaceID != PWORKSPACE->m_iID || nd.isMaster)
continue;

if (onRight) {
slaveAccumulatedHeightR += slaveAverageHeightR * nd.percSize;
} else {
slaveAccumulatedHeightL += slaveAverageHeightL * nd.percSize;
}
onRight = !onRight;
}
onRight = true;
}

for (auto& nd : m_lMasterNodesData) {
if (nd.workspaceID != PWORKSPACE->m_iID || nd.isMaster)
continue;
Expand All @@ -449,6 +508,16 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
if (HEIGHT > heightLeft * 0.9f && slavesLeft > 1)
HEIGHT = heightLeft * 0.9f;

if (*PSMARTRESIZING) {
if (onRight) {
nd.percSize *= WSSIZE.y / slaveAccumulatedHeightR;
HEIGHT = slaveAverageHeightR * nd.percSize;
} else {
nd.percSize *= WSSIZE.y / slaveAccumulatedHeightL;
HEIGHT = slaveAverageHeightL * nd.percSize;
}
}

nd.size = Vector2D(WIDTH, HEIGHT);
nd.position = WSPOS + Vector2D(nextX, nextY);
applyNodeDataToWindow(&nd);
Expand Down Expand Up @@ -599,11 +668,20 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
const auto PWORKSPACEDATA = getMasterWorkspaceData(PMONITOR->activeWorkspace);
static auto* const ALWAYSCENTER = &g_pConfigManager->getConfigValuePtr("master:always_center_master")->intValue;
static auto* const PSMARTRESIZING = &g_pConfigManager->getConfigValuePtr("master:smart_resizing")->intValue;

eOrientation orientation = PWORKSPACEDATA->orientation;
bool centered = orientation == ORIENTATION_CENTER && (*ALWAYSCENTER == 1);
double delta = 0;

const bool DISPLAYBOTTOM = STICKS(PWINDOW->m_vPosition.y + PWINDOW->m_vSize.y, PMONITOR->vecPosition.y + PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y);
const bool DISPLAYRIGHT = STICKS(PWINDOW->m_vPosition.x + PWINDOW->m_vSize.x, PMONITOR->vecPosition.x + PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x);
const bool DISPLAYTOP = STICKS(PWINDOW->m_vPosition.y, PMONITOR->vecPosition.y + PMONITOR->vecReservedTopLeft.y);
const bool DISPLAYLEFT = STICKS(PWINDOW->m_vPosition.x, PMONITOR->vecPosition.x + PMONITOR->vecReservedTopLeft.x);

const bool LEFT = corner == CORNER_TOPLEFT || corner == CORNER_BOTTOMLEFT;
const bool TOP = corner == CORNER_TOPLEFT || corner == CORNER_TOPRIGHT;

if (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) == 1 && !centered)
return;

Expand All @@ -626,19 +704,93 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne
// check the up/down resize
const auto RESIZEDELTA = PWORKSPACEDATA->orientation % 2 == 1 ? pixResize.x : pixResize.y;

if (RESIZEDELTA != 0) {
if (PNODE->isMaster && getMastersOnWorkspace(PNODE->workspaceID) > 1) {
// check master size
const auto SIZE = PWORKSPACEDATA->orientation % 2 == 1 ?
(PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x) / getMastersOnWorkspace(PNODE->workspaceID) :
(PMONITOR->vecSize.y - PMONITOR->vecReservedTopLeft.y - PMONITOR->vecReservedBottomRight.y) / getMastersOnWorkspace(PNODE->workspaceID);
PNODE->percSize = std::clamp(PNODE->percSize + RESIZEDELTA / SIZE, 0.05, 1.95);
} else if (!PNODE->isMaster && (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) - getMastersOnWorkspace(PNODE->workspaceID)) > 1) {
const auto SIZE = PWORKSPACEDATA->orientation % 2 == 1 ? (PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x) /
(getNodesOnWorkspace(PNODE->workspaceID) - getMastersOnWorkspace(PNODE->workspaceID)) :
(PMONITOR->vecSize.y - PMONITOR->vecReservedTopLeft.y - PMONITOR->vecReservedBottomRight.y) /
(getNodesOnWorkspace(PNODE->workspaceID) - getMastersOnWorkspace(PNODE->workspaceID));
PNODE->percSize = std::clamp(PNODE->percSize + RESIZEDELTA / SIZE, 0.05, 1.95);
if (!*PSMARTRESIZING) {
if (RESIZEDELTA != 0) {
if (PNODE->isMaster && getMastersOnWorkspace(PNODE->workspaceID) > 1) {
// check master size
const auto SIZE = PWORKSPACEDATA->orientation % 2 == 1 ?
(PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x) / getMastersOnWorkspace(PNODE->workspaceID) :
(PMONITOR->vecSize.y - PMONITOR->vecReservedTopLeft.y - PMONITOR->vecReservedBottomRight.y) / getMastersOnWorkspace(PNODE->workspaceID);
PNODE->percSize = std::clamp(PNODE->percSize + RESIZEDELTA / SIZE, 0.05, 1.95);
} else if (!PNODE->isMaster && (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) - getMastersOnWorkspace(PNODE->workspaceID)) > 1) {
const auto SIZE = PWORKSPACEDATA->orientation % 2 == 1 ? (PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x) /
(getNodesOnWorkspace(PNODE->workspaceID) - getMastersOnWorkspace(PNODE->workspaceID)) :
(PMONITOR->vecSize.y - PMONITOR->vecReservedTopLeft.y - PMONITOR->vecReservedBottomRight.y) /
(getNodesOnWorkspace(PNODE->workspaceID) - getMastersOnWorkspace(PNODE->workspaceID));
PNODE->percSize = std::clamp(PNODE->percSize + RESIZEDELTA / SIZE, 0.05, 1.95);
}
}
} else {
const auto MASTERS = getMastersOnWorkspace(PNODE->workspaceID);
const auto WINDOWS = getNodesOnWorkspace(PNODE->workspaceID);
const auto STACKWINDOWS = WINDOWS - MASTERS;
const auto WSSIZE = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;

const bool isStackVertical = orientation % 2 == 0;
auto nodesInSameColumn = PNODE->isMaster ? MASTERS : STACKWINDOWS;
if (orientation == ORIENTATION_CENTER && !PNODE->isMaster)
nodesInSameColumn /= 2;

if (RESIZEDELTA != 0 && nodesInSameColumn > 1) {
const auto NODEIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *PNODE);
const auto REVNODEIT = std::find(m_lMasterNodesData.rbegin(), m_lMasterNodesData.rend(), *PNODE);
const auto SIZE = isStackVertical ?
(PMONITOR->vecSize.y - PMONITOR->vecReservedTopLeft.y - PMONITOR->vecReservedBottomRight.y) / nodesInSameColumn:
(PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x) / nodesInSameColumn;

const float totalSize = isStackVertical ? WSSIZE.y : WSSIZE.x;
const float minSize = totalSize / nodesInSameColumn * 0.2;
const bool resizePrevNodes = isStackVertical ? (TOP || DISPLAYBOTTOM) && !DISPLAYTOP : (LEFT || DISPLAYRIGHT) && !DISPLAYLEFT;

int nodesLeft = 0;
float sizeLeft = 0;
int nodeCount = 0;
// check the sizes of all the nodes to be resized for later calculation
auto checkNodesLeft = [&sizeLeft, &nodesLeft, orientation, isStackVertical, &nodeCount, PNODE](auto it) {
if (it.isMaster != PNODE->isMaster || it.workspaceID != PNODE->workspaceID)
return;
nodeCount++;
if (!it.isMaster && orientation == ORIENTATION_CENTER && nodeCount % 2 == 1)
return;
sizeLeft += isStackVertical ? it.size.y : it.size.x;
nodesLeft++;
};
float resizeDiff;
if (resizePrevNodes) {
std::for_each(std::next(REVNODEIT), m_lMasterNodesData.rend(), checkNodesLeft);
resizeDiff = -RESIZEDELTA;
} else {
std::for_each(std::next(NODEIT), m_lMasterNodesData.end(), checkNodesLeft);
resizeDiff = RESIZEDELTA;
}

const float nodeSize = isStackVertical ? PNODE->size.y : PNODE->size.x;
const float maxSizeIncrease = sizeLeft - nodesLeft * minSize;
const float maxSizeDecrease = minSize - nodeSize;

// leaves enough room for the other nodes
resizeDiff = std::clamp(resizeDiff, maxSizeDecrease, maxSizeIncrease);
PNODE->percSize += resizeDiff / SIZE;

// resize the other nodes
nodeCount = 0;
auto resizeNodesLeft = [maxSizeIncrease, resizeDiff, minSize, orientation, isStackVertical, SIZE, &nodeCount, nodesLeft, PNODE](auto &it) {
if (it.isMaster != PNODE->isMaster || it.workspaceID != PNODE->workspaceID)
return;
nodeCount++;
// if center orientation, only resize when on the same side
if (!it.isMaster && orientation == ORIENTATION_CENTER && nodeCount % 2 == 1)
return;
const float size = isStackVertical ? it.size.y : it.size.x;
const float resizeDeltaForEach = maxSizeIncrease != 0 ?
resizeDiff * (size - minSize) / maxSizeIncrease : resizeDiff / nodesLeft;
it.percSize -= resizeDeltaForEach / SIZE;
};
if (resizePrevNodes) {
std::for_each(std::next(REVNODEIT), m_lMasterNodesData.rend(), resizeNodesLeft);
} else {
std::for_each(std::next(NODEIT), m_lMasterNodesData.end(), resizeNodesLeft);
}
}
}

Expand Down

0 comments on commit 19bbdee

Please sign in to comment.