Skip to content

Commit 64faa73

Browse files
committed
Add xfact option to center any number of stacks
1 parent 388efc8 commit 64faa73

File tree

4 files changed

+69
-48
lines changed

4 files changed

+69
-48
lines changed

README.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ plugin {
2424
auto_promote=0
2525
auto_demote=0
2626
order=row
27+
xfact=0.0
2728
}
2829
}
2930
}
@@ -32,18 +33,22 @@ plugin {
3233
### Configuration variable differences in comparison to Master Layout
3334
* `stacks` The number of *total* stacks, including the master.
3435
* `mfact` If this is set to 0 the master is the same size as the stacks. So if there is one master and 2 stacks they are all 1/3rd of the screen width(or height). Master and 3 stacks they are all 1/4th etc.
35-
* `single_mfact` The size of a single centered master window, when center_single_master is set.
36+
* `single_mfact` The size of a single centered master window, when center_single_master is set.
3637
* `center_single_master` When there is a single window on the screen it is centered instead of taking up the entire monitor. This replaces the existing `always_center_master` and has slightly different behavior.
3738
* `auto_promote` After tiled window is created, add extra master if workspace has this many windows.
3839
* `auto_demote` After tiled window is destroyed, remove extra master if workspace has less than this many windows.
3940
* `order` The order slave windows are filled in. (row/column/rrow/rcolumn)
41+
* `xfact` X-factor, mfact for the whole layout, add extra margins to center any number of stacks using workspace rules (see below). Generic replacement for single\* options.
4042

4143
### Workspace layout options
4244
All configuration variables are also usable as workspace rule layout options. Just prefix the setting name with 'nstack-'
4345

44-
* `workspace = 2,layoutopt:nstack-stacks:2,layoutopt:nstack-single_mfact:0.85`
45-
* `workspace = w[tv1-3],layoutopt:nstack-stacks:2,layoutopt:nstack-mfact:0.6667`
46-
* `workspace = w[tv4-20],layoutopt:nstack-stacks:3,layoutopt:nstack-mfact:0,layoutopt:nstack-auto_promote:8,layoutopt:nstack-auto_demote:6`
46+
```conf
47+
# center single master and two stacks using 2/3 of screen when 1-3 windows are open
48+
workspace = w[tv1-3],layoutopt:nstack-stacks:2,layoutopt:nstack-xfact:0.6667
49+
# add third stack when 4th window opened and fill whole screen, auto split master when 8th window opened etc
50+
workspace = w[tv4-20],layoutopt:nstack-stacks:3,layoutopt:nstack-auto_promote:8,layoutopt:nstack-auto_demote:6
51+
```
4752

4853
# Dispatchers
4954

main.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
3636
HyprlandAPI::addConfigValue(PHANDLE, "plugin:nstack:layout:center_single_master", Hyprlang::INT{0});
3737
HyprlandAPI::addConfigValue(PHANDLE, "plugin:nstack:layout:mfact", Hyprlang::FLOAT{0.5f});
3838
HyprlandAPI::addConfigValue(PHANDLE, "plugin:nstack:layout:single_mfact", Hyprlang::FLOAT{0.5f});
39+
HyprlandAPI::addConfigValue(PHANDLE, "plugin:nstack:layout:xfact", Hyprlang::FLOAT{0.0f});
3940
HyprlandAPI::addConfigValue(PHANDLE, "plugin:nstack:layout:auto_promote", Hyprlang::INT{0});
4041
HyprlandAPI::addConfigValue(PHANDLE, "plugin:nstack:layout:auto_demote", Hyprlang::INT{1});
4142
HyprlandAPI::addConfigValue(PHANDLE, "plugin:nstack:layout:order", Hyprlang::STRING{"row"});

nstackLayout.cpp

Lines changed: 58 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,17 @@ static void applyWorkspaceLayoutOptions(SNstackWorkspaceData* wsData) {
131131
}
132132
wsData->single_master_factor = wssmfact;
133133

134+
static auto* const XFACT = (Hyprlang::FLOAT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:nstack:layout:xfact")->getDataStaticPtr();
135+
auto wsxfact = **XFACT;
136+
137+
if (wslayoutopts.contains("nstack-xfact")) {
138+
std::string xfactstr = wslayoutopts.at("nstack-xfact");
139+
try {
140+
wsxfact = std::stof(xfactstr);
141+
} catch (std::exception& e) { Debug::log(ERR, "Nstack layoutopt nstack-xfact format error: {}", e.what()); }
142+
}
143+
wsData->x_factor = wsxfact;
144+
134145
static auto* const SSFACT = (Hyprlang::FLOAT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:nstack:layout:special_scale_factor")->getDataStaticPtr();
135146
auto wsssfact = **SSFACT;
136147
if (wslayoutopts.contains("nstack-special_scale_factor")) {
@@ -439,56 +450,61 @@ void CHyprNstackLayout::calculateWorkspace(PHLWORKSPACE PWORKSPACE) {
439450

440451
auto MCONTAINERPOS = Vector2D(0.0f, 0.0f);
441452
auto MCONTAINERSIZE = Vector2D(0.0f, 0.0f);
442-
453+
auto MARGIN = Vector2D(0.0f, 0.0f);
454+
auto TOPLEFT = PMONITOR->vecReservedTopLeft;
455+
auto BOTTOMRIGHT = PMONITOR->vecReservedBottomRight;
456+
if (PWORKSPACEDATA->x_factor > 0.0f && PWORKSPACEDATA->x_factor < 1.0f) {
457+
MARGIN = Vector2D(orientation % 2 == 0 ? (1.0f - PWORKSPACEDATA->x_factor) * PMONITOR->vecSize.x / 2.f : 0.0f,
458+
orientation % 2 == 1 ? (1.0f - PWORKSPACEDATA->x_factor) * PMONITOR->vecSize.y / 2.f : 0.0f);
459+
TOPLEFT += MARGIN;
460+
BOTTOMRIGHT += MARGIN;
461+
}
443462
if (ONLYMASTERS) {
444463
if (centerMasterWindow) {
445464

446465
if (!PMASTERNODE->masterAdjusted)
447466
PMASTERNODE->percMaster = PWORKSPACEDATA->single_master_factor ? PWORKSPACEDATA->single_master_factor : 0.5f;
448467

449468
if (orientation == NSTACK_ORIENTATION_TOP || orientation == NSTACK_ORIENTATION_BOTTOM) {
450-
const float HEIGHT = (PMONITOR->vecSize.y - PMONITOR->vecReservedTopLeft.y - PMONITOR->vecReservedBottomRight.y) * PMASTERNODE->percMaster;
469+
const float HEIGHT = (PMONITOR->vecSize.y - TOPLEFT.y - BOTTOMRIGHT.y) * PMASTERNODE->percMaster;
451470
float CENTER_OFFSET = (PMONITOR->vecSize.y - HEIGHT) / 2;
452-
MCONTAINERSIZE = Vector2D(PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x, HEIGHT);
453-
MCONTAINERPOS = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition + Vector2D(0.0, CENTER_OFFSET);
471+
MCONTAINERSIZE = Vector2D(PMONITOR->vecSize.x - TOPLEFT.x - BOTTOMRIGHT.x, HEIGHT);
472+
MCONTAINERPOS = TOPLEFT + PMONITOR->vecPosition + Vector2D(0.0, CENTER_OFFSET);
454473
} else {
455-
const float WIDTH = (PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x) * PMASTERNODE->percMaster;
474+
const float WIDTH = (PMONITOR->vecSize.x - TOPLEFT.x - BOTTOMRIGHT.x) * PMASTERNODE->percMaster;
456475
float CENTER_OFFSET = (PMONITOR->vecSize.x - WIDTH) / 2;
457-
MCONTAINERSIZE = Vector2D(WIDTH, PMONITOR->vecSize.y - PMONITOR->vecReservedTopLeft.y - PMONITOR->vecReservedBottomRight.y);
458-
MCONTAINERPOS = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition + Vector2D(CENTER_OFFSET, 0.0);
476+
MCONTAINERSIZE = Vector2D(WIDTH, PMONITOR->vecSize.y - TOPLEFT.y - BOTTOMRIGHT.y);
477+
MCONTAINERPOS = TOPLEFT + PMONITOR->vecPosition + Vector2D(CENTER_OFFSET, 0.0);
459478
}
460479
} else {
461-
MCONTAINERPOS = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition;
462-
MCONTAINERSIZE = Vector2D(PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x,
463-
PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y);
480+
MCONTAINERPOS = TOPLEFT + PMONITOR->vecPosition;
481+
MCONTAINERSIZE = Vector2D(PMONITOR->vecSize.x - TOPLEFT.x - BOTTOMRIGHT.x, PMONITOR->vecSize.y - BOTTOMRIGHT.y - TOPLEFT.y);
464482
}
465483
} else {
466-
const float MASTERSIZE = orientation % 2 == 0 ? (PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x) * PMASTERNODE->percMaster :
467-
(PMONITOR->vecSize.y - PMONITOR->vecReservedTopLeft.y - PMONITOR->vecReservedBottomRight.y) * PMASTERNODE->percMaster;
484+
const float MASTERSIZE = orientation % 2 == 0 ? (PMONITOR->vecSize.x - TOPLEFT.x - BOTTOMRIGHT.x) * PMASTERNODE->percMaster :
485+
(PMONITOR->vecSize.y - TOPLEFT.y - BOTTOMRIGHT.y) * PMASTERNODE->percMaster;
468486

469487
if (orientation == NSTACK_ORIENTATION_RIGHT) {
470-
MCONTAINERPOS = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition +
471-
Vector2D(PMONITOR->vecSize.x - MASTERSIZE - PMONITOR->vecReservedBottomRight.x - PMONITOR->vecReservedTopLeft.x, 0.0f);
472-
MCONTAINERSIZE = Vector2D(MASTERSIZE, PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y);
488+
MCONTAINERPOS = TOPLEFT + PMONITOR->vecPosition + Vector2D(PMONITOR->vecSize.x - MASTERSIZE - BOTTOMRIGHT.x - TOPLEFT.x, 0.0f);
489+
MCONTAINERSIZE = Vector2D(MASTERSIZE, PMONITOR->vecSize.y - BOTTOMRIGHT.y - TOPLEFT.y);
473490
} else if (orientation == NSTACK_ORIENTATION_LEFT) {
474-
MCONTAINERPOS = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition;
475-
MCONTAINERSIZE = Vector2D(MASTERSIZE, PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y);
491+
MCONTAINERPOS = TOPLEFT + PMONITOR->vecPosition;
492+
MCONTAINERSIZE = Vector2D(MASTERSIZE, PMONITOR->vecSize.y - BOTTOMRIGHT.y - TOPLEFT.y);
476493
} else if (orientation == NSTACK_ORIENTATION_TOP) {
477-
MCONTAINERPOS = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition;
478-
MCONTAINERSIZE = Vector2D(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PMONITOR->vecReservedTopLeft.x, MASTERSIZE);
494+
MCONTAINERPOS = TOPLEFT + PMONITOR->vecPosition;
495+
MCONTAINERSIZE = Vector2D(PMONITOR->vecSize.x - BOTTOMRIGHT.x - TOPLEFT.x, MASTERSIZE);
479496
} else if (orientation == NSTACK_ORIENTATION_BOTTOM) {
480-
MCONTAINERPOS = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition +
481-
Vector2D(0.0f, PMONITOR->vecSize.y - MASTERSIZE - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y);
482-
MCONTAINERSIZE = Vector2D(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PMONITOR->vecReservedTopLeft.x, MASTERSIZE);
497+
MCONTAINERPOS = TOPLEFT + PMONITOR->vecPosition + Vector2D(0.0f, PMONITOR->vecSize.y - MASTERSIZE - BOTTOMRIGHT.y - TOPLEFT.y);
498+
MCONTAINERSIZE = Vector2D(PMONITOR->vecSize.x - BOTTOMRIGHT.x - TOPLEFT.x, MASTERSIZE);
483499

484500
} else if (orientation == NSTACK_ORIENTATION_HCENTER) {
485-
float CENTER_OFFSET = (PMONITOR->vecSize.x - MASTERSIZE) / 2;
486-
MCONTAINERSIZE = Vector2D(MASTERSIZE, PMONITOR->vecSize.y - PMONITOR->vecReservedTopLeft.y - PMONITOR->vecReservedBottomRight.y);
487-
MCONTAINERPOS = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition + Vector2D(CENTER_OFFSET, 0.0);
501+
float CENTER_OFFSET = (PMONITOR->vecSize.x - MASTERSIZE - 2.f * MARGIN.x) / 2;
502+
MCONTAINERSIZE = Vector2D(MASTERSIZE, PMONITOR->vecSize.y - TOPLEFT.y - BOTTOMRIGHT.y);
503+
MCONTAINERPOS = TOPLEFT + PMONITOR->vecPosition + Vector2D(CENTER_OFFSET, 0.0);
488504
} else if (orientation == NSTACK_ORIENTATION_VCENTER) {
489-
float CENTER_OFFSET = (PMONITOR->vecSize.y - MASTERSIZE) / 2;
490-
MCONTAINERSIZE = Vector2D(PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x, MASTERSIZE);
491-
MCONTAINERPOS = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition + Vector2D(0.0, CENTER_OFFSET);
505+
float CENTER_OFFSET = (PMONITOR->vecSize.y - MASTERSIZE - 2.f * MARGIN.y) / 2;
506+
MCONTAINERSIZE = Vector2D(PMONITOR->vecSize.x - TOPLEFT.x - BOTTOMRIGHT.x, MASTERSIZE);
507+
MCONTAINERPOS = TOPLEFT + PMONITOR->vecPosition + Vector2D(0.0, CENTER_OFFSET);
492508
}
493509
}
494510

@@ -539,19 +555,18 @@ void CHyprNstackLayout::calculateWorkspace(PHLWORKSPACE PWORKSPACE) {
539555
PWORKSPACEDATA->stackNodeCount.assign(numStacks + 1, 0);
540556
PWORKSPACEDATA->stackPercs.resize(numStacks + 1, 1.0f);
541557

542-
float stackNodeSizeLeft = orientation % 2 == 1 ? PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PMONITOR->vecReservedTopLeft.x :
543-
PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y;
558+
float stackNodeSizeLeft = orientation % 2 == 1 ? PMONITOR->vecSize.x - BOTTOMRIGHT.x - TOPLEFT.x : PMONITOR->vecSize.y - BOTTOMRIGHT.y - TOPLEFT.y;
544559

545560
int stackNum = 0;
546561
std::vector<float> nodeSpaceLeft(numStacks, stackNodeSizeLeft);
547562
std::vector<float> nodeNextCoord(numStacks, 0);
548563
std::vector<Vector2D> stackCoords(numStacks, Vector2D(0, 0));
549564

550-
const float STACKSIZE = orientation % 2 == 1 ? (PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y - PMASTERNODE->size.y) / numStacks :
551-
(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PMONITOR->vecReservedTopLeft.x - PMASTERNODE->size.x) / numStacks;
565+
const float STACKSIZE = orientation % 2 == 1 ? (PMONITOR->vecSize.y - BOTTOMRIGHT.y - TOPLEFT.y - PMASTERNODE->size.y) / numStacks :
566+
(PMONITOR->vecSize.x - BOTTOMRIGHT.x - TOPLEFT.x - PMASTERNODE->size.x) / numStacks;
552567

553-
const float STACKSIZEBEFORE = numStackBefore ? ((STACKSIZE * numStacks) / 2) / numStackBefore : 0.0f;
554-
const float STACKSIZEAFTER = numStackAfter ? ((STACKSIZE * numStacks) / 2) / numStackAfter : 0.0f;
568+
const float STACKSIZEBEFORE = numStackBefore ? ((STACKSIZE * numStacks) / 2) / numStackBefore : 0.0f;
569+
const float STACKSIZEAFTER = numStackAfter ? ((STACKSIZE * numStacks) / 2) / numStackAfter : 0.0f;
555570

556571
//Pre calculate each stack's coordinates so we can take into account manual resizing
557572
if (orientation == NSTACK_ORIENTATION_LEFT || orientation == NSTACK_ORIENTATION_TOP) {
@@ -574,11 +589,10 @@ void CHyprNstackLayout::calculateWorkspace(PHLWORKSPACE PWORKSPACE) {
574589
//The Vector here isn't 'x,y', it is 'stack start, stack end'
575590
double coordAdjust = 0;
576591
if (i == numStackBefore && numStackAfter) {
577-
coordAdjust = orientation % 2 == 1 ? PMASTERNODE->position.y + PMASTERNODE->size.y - PMONITOR->vecPosition.y - PMONITOR->vecReservedTopLeft.y :
578-
PMASTERNODE->position.x + PMASTERNODE->size.x - PMONITOR->vecPosition.x - PMONITOR->vecReservedTopLeft.x;
592+
coordAdjust = orientation % 2 == 1 ? PMASTERNODE->position.y + PMASTERNODE->size.y - PMONITOR->vecPosition.y - TOPLEFT.y :
593+
PMASTERNODE->position.x + PMASTERNODE->size.x - PMONITOR->vecPosition.x - TOPLEFT.x;
579594
}
580-
float monMax = orientation % 2 == 1 ? PMONITOR->vecSize.y - PMONITOR->vecReservedTopLeft.y - PMONITOR->vecReservedBottomRight.y :
581-
PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x;
595+
float monMax = orientation % 2 == 1 ? PMONITOR->vecSize.y - TOPLEFT.y - BOTTOMRIGHT.y : PMONITOR->vecSize.x - TOPLEFT.x - BOTTOMRIGHT.x;
582596
float stackStart = 0.0f;
583597
if (i == numStackBefore && numStackAfter) {
584598
stackStart = coordAdjust;
@@ -593,22 +607,22 @@ void CHyprNstackLayout::calculateWorkspace(PHLWORKSPACE PWORKSPACE) {
593607
if (orientation == NSTACK_ORIENTATION_LEFT && i >= numStacks - 1) {
594608
scaledSize = monMax - stackStart;
595609
} else if (orientation == NSTACK_ORIENTATION_RIGHT && i >= numStacks - 1) {
596-
scaledSize = (PMASTERNODE->position.x - PMONITOR->vecPosition.x - PMONITOR->vecReservedTopLeft.x) - stackStart;
610+
scaledSize = (PMASTERNODE->position.x - PMONITOR->vecPosition.x - TOPLEFT.x) - stackStart;
597611
} else if (orientation == NSTACK_ORIENTATION_TOP && i >= numStacks - 1) {
598612
scaledSize = monMax - stackStart;
599613
} else if (orientation == NSTACK_ORIENTATION_BOTTOM && i >= numStacks - 1) {
600-
scaledSize = (PMASTERNODE->position.y - PMONITOR->vecPosition.y - PMONITOR->vecReservedTopLeft.y) - stackStart;
614+
scaledSize = (PMASTERNODE->position.y - PMONITOR->vecPosition.y - TOPLEFT.y) - stackStart;
601615
} else if (orientation == NSTACK_ORIENTATION_HCENTER) {
602616
if (i >= numStacks - 1) {
603617
scaledSize = monMax - stackStart;
604618
} else if (i == numStacks - 2) {
605-
scaledSize = (PMASTERNODE->position.x - PMONITOR->vecPosition.x - PMONITOR->vecReservedTopLeft.x) - stackStart;
619+
scaledSize = (PMASTERNODE->position.x - PMONITOR->vecPosition.x - TOPLEFT.x) - stackStart;
606620
}
607621
} else if (orientation == NSTACK_ORIENTATION_VCENTER) {
608622
if (i >= numStacks - 1) {
609623
scaledSize = monMax - stackStart;
610624
} else if (i == numStacks - 2) {
611-
scaledSize = (PMASTERNODE->position.y - PMONITOR->vecPosition.y - PMONITOR->vecReservedTopLeft.y) - stackStart;
625+
scaledSize = (PMASTERNODE->position.y - PMONITOR->vecPosition.y - TOPLEFT.y) - stackStart;
612626
}
613627
}
614628
stackCoords[i] = Vector2D(stackStart, stackStart + scaledSize);
@@ -623,9 +637,9 @@ void CHyprNstackLayout::calculateWorkspace(PHLWORKSPACE PWORKSPACE) {
623637

624638
Vector2D stackPos = stackCoords[stackNum];
625639
if (orientation % 2 == 0) {
626-
nd.position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition + Vector2D(stackPos.x, nodeNextCoord[stackNum]);
640+
nd.position = TOPLEFT + PMONITOR->vecPosition + Vector2D(stackPos.x, nodeNextCoord[stackNum]);
627641
} else {
628-
nd.position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition + Vector2D(nodeNextCoord[stackNum], stackPos.x);
642+
nd.position = TOPLEFT + PMONITOR->vecPosition + Vector2D(nodeNextCoord[stackNum], stackPos.x);
629643
}
630644

631645
int nodeDiv = slavesTotal / numStacks;

nstackLayout.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ struct SNstackWorkspaceData {
7070
int no_gaps_when_only = 0;
7171
float master_factor = 0.0f;
7272
float single_master_factor = 0.5f;
73+
float x_factor = 0.0f;
7374
float special_scale_factor = 0.8f;
7475
eColOrientation orientation = NSTACK_ORIENTATION_LEFT;
7576
eColOrder order = NSTACK_ORDER_ROW;

0 commit comments

Comments
 (0)