Cycling through custom areas

It is possible to cycle through left half, fullscreen, right half (and optionally quarters).
My issue is that I use a 21:9 screen with a width of 3440 pixels. So I spend most time of the day working with three vertical 'spaces' of different widths: 1000px, 1440px, 1000px. I defined appropriate snap areas and recorded shortcuts for all of them, but sometimes I also would like to work on basically 16:9 with a narrow side window (2440px, 1000px)

It would be cool if it's somehow possible to use a single shortcut to cycle between two or more widths / snap areas like:
(0, 1000) → (0, 1720) → (0, 2440) → (0, 1000)

Generalizing this concept to snap areas would also help for people who want the 'cycling' feature without being restricted to full-height windows.

Thanks in advance for your reply!

You can use some custom script to cycle through things. Here is an example using the new "Real Java Script" action (requires latest BTT):

async function cycleThrough () {

let variableName = 'windowMoveCounter';;
let variable = await callBTT('get_number_variable', {variable_name: variableName});;

	if(variable === undefined) {
		await callBTT('set_number_variable', {variable_name: variableName, to: 1});
		variable = 1;
	}
		
	if(variable == 1) {
		callBTT('trigger_named_async_without_response', {trigger_name: 'moveLeft'});
	} else if(variable == 2) {
		callBTT('trigger_named_async_without_response', {trigger_name: 'moveRight'});
	} else if(variable == 3) {
		callBTT('trigger_named_async_without_response', {trigger_name: 'moveTop'});
	} else if(variable == 4) {
		callBTT('trigger_named_async_without_response', {trigger_name: 'moveBottom'});
	} else if(variable % 5 == 0) { 
		await callBTT('set_number_variable', {variable_name: variableName, to: 0});
		variable = 0;
	}

	// increase the variable callBTT
	await callBTT('set_number_variable', {variable_name: variableName, to: variable+1});


    // return to BTT
	returnToBTT(variable);

}


cycleThrough();

It cycles through the values 0-4 and triggers different named triggers while doing that. These named triggers need to be defined in the "Named & Other Triggers" section and also allow you to trigger a custom snap area (or use the "Custom resize/move" action.)

1 Like

Thanks a lot for the quick reply and the great solution with the custom scripts, didn't know this was possible! I modified the script a little bit to have a shortcut to cycle between two "lefts" and one for two "right" options but it works great :blush:

1 Like

Thanks to @Andreas_Hegenberg, I was able to achieve exactly what I wanted (tbh for years, never got around to trying and asking around).

It behaves just like I wanted:
When moving a window from one side to the other, it automatically takes the smaller size, all the way to the right / left. This is done by checking the didMove variable.
After having moved a window from one side to the other, repeating the shortcut more times just toggles between the moveLeft and moveLeftWide / moveRight and moveRightWide layouts.

These are my snap areas:

moveLeft                 moveLeftWide

+----+---------+----+    +----+---------+----+
|xxxx|         |    |    |xxxx|xxxxxxxxx|    |
|xxxx|         |    |    |xxxx|xxxxxxxxx|    |
+----+---------+----+    +----+---------+----+
moveRight                moveRightWide

+----+---------+----+    +----+---------+----+
|    |         |xxxx|    |    |xxxxxxxxx|xxxx|
|    |         |xxxx|    |    |xxxxxxxxx|xxxx|
+----+---------+----+    +----+---------+----+

This is my script for the left side:

async function cycleThrough () {

	let moveWideName = 'windowLeftMoveWide';
	let didMoveName = 'didMove';
	let moveWide = await callBTT('get_number_variable', {variable_name: moveWideName});
	let didMove = await callBTT('get_string_variable', {variable_name: didMoveName});

	if (moveWide === undefined) {
		await callBTT('set_number_variable', {variable_name: moveWideName, to: false});
		moveWide = false;
	}
	
	if (didMove === undefined) {
		await callBTT('set_string_variable', {variable_name: didMoveName, to: 'left'});
		didMove = 'left';
	}
	
	if (didMove == 'right') {
		moveWide = false;
	}
		
	if (moveWide) {
		callBTT('trigger_named_async_without_response', {trigger_name: 'moveLeftWide'});
	}
	else {
		callBTT('trigger_named_async_without_response', {trigger_name: 'moveLeft'});
	}

	// increase the variable callBTT
	await callBTT('set_number_variable', {variable_name: moveWideName, to: !moveWide});


	// set the variable didMove
	await callBTT('set_string_variable', {variable_name: didMoveName, to: 'left'});

    // return to BTT
	returnToBTT(variable);

}

cycleThrough();

And here almost the same stuff for the right:

async function cycleThrough () {

	let moveWideName = 'windowRightMoveWide';
	let didMoveName = 'didMove';
	let moveWide = await callBTT('get_number_variable', {variable_name: moveWideName});
	let didMove = await callBTT('get_string_variable', {variable_name: didMoveName});

	if (moveWide === undefined) {
		await callBTT('set_number_variable', {variable_name: moveWideName, to: false});
		moveWide = false;
	}
	
	if (didMove === undefined) {
		await callBTT('set_string_variable', {variable_name: didMoveName, to: 'right'});
		didMove = 'right';
	}
	
	if (didMove == 'left') {
		moveWide = false;
	}
		
	if (moveWide) {
		callBTT('trigger_named_async_without_response', {trigger_name: 'moveRightWide'});
	}
	else {
		callBTT('trigger_named_async_without_response', {trigger_name: 'moveRight'});
	}

	// increase the variable callBTT
	await callBTT('set_number_variable', {variable_name: moveWideName, to: !moveWide});


	// set the variable didMove
	await callBTT('set_string_variable', {variable_name: didMoveName, to: 'right'});

	// return to BTT
	returnToBTT(moveWide);
}

cycleThrough();
1 Like

Great, thanks for sharing!

1 Like

Thanks for your help and the great tool!

Here's an improved, generalized version of this:

async function cycleThrough(triggers) {
  let cycleName = "cycle-" + triggers.join('-'); // Build a unique counter name
  let counterValue = await callBTT('get_number_variable', {variable_name: cycleName});

  // Initialize the value in BTT
  if(counterValue === undefined) {
	await callBTT('set_number_variable', {variable_name: cycleName, to: 0});
	counterValue = 0;
  }
    
  // Cycle through them
  let modCounter = counterValue % triggers.length;	
  callBTT('trigger_named_async_without_response', {trigger_name: triggers[modCounter]});
  
  // Increment the counter
  await callBTT('set_number_variable', {variable_name: cycleName, to: modCounter+1});

  // return to BTT
  returnToBTT(counterValue);

}

// Cycle through the given triggers
cycleThrough([
  "leftHalf",
  "leftTwoThirds",
  "leftOneThird"
]);

(You still have to create the referenced Reusable Named Triggers.)

@Andreas_Hegenberg: Is there some global place that helpers, like the cycleThrough could be added so that the trigger just becomes the usage of that method?

2 Likes

It would also be useful to be able to reset the counter to zero on the first press of the key combination. As it stands, the cycle remembers the last count.

I have slightly modified your code to add a time limit between repetitions of the key combination before resetting the counter.

With the following code, if you wait more that one second (1000 ms), the cycle is reset to the first value (leftHalf):

async function cycleThrough(triggers) {
  let cycleName = "cycle_" + triggers.join('-'); // Build a unique counter name
  let counterValue = await callBTT('get_number_variable', {variable_name: cycleName});
  let lastTriggeredTime = await callBTT('get_number_variable', {variable_name: cycleName + "_Timestamp"});

  // Initialize or reset the value in BTT
  if(counterValue === undefined || lastTriggeredTime === undefined || (Date.now() - lastTriggeredTime > 1000) ) {
	await callBTT('set_number_variable', {variable_name: cycleName, to: 0});
	counterValue = 0;
  }
    
  // Cycle through them
  let modCounter = counterValue % triggers.length;	
  callBTT('trigger_named_async_without_response', {trigger_name: triggers[modCounter]});
  
  // Increment the counter
  await callBTT('set_number_variable', {variable_name: cycleName, to: modCounter+1});
  
  // Save the date
  await callBTT('set_number_variable', {variable_name: cycleName + "_Timestamp", to: Date.now()});

  // return to BTT
  returnToBTT(counterValue);

}

// Cycle through the given triggers
cycleThrough([
  "leftHalf",
  "leftTwoThirds",
  "leftThird"
]);
2 Likes