using System;
using System.Drawing;
// This script is intended for large monitors where a user has "snapped" a windows to each quarter of the screen by dragging it into the corner.
// Running the script will take the currently focused window, expand it to take up 70% of the width and 70% of the height of the monitor, and
// then expand or contract the other windows in the other corners to fit. Windows that are not in a corner will be unaffected. If the windows are
// already expanded/contracted, running the script with the largest window focused will revert back to each window taking up a quarter of the screen.
public static class DisplayFusionFunction
{
// the percentage of the screen, width and height, to set the window to
public static int percentWidth = 70;
public static int percentHeight = 70;
// sometimes putting a window into the corner of the screen results in it being a few pixels off, this is the number of pixels it can be off and still get picked up
public static int tolerence = 10;
// print out some debug info
public static bool debug = false;
// enum describing the corner the window is in
public enum Quad {TopLeft, BottomLeft, TopRight, BottomRight, None}
// enum describing the new size of the window
public enum Relative {WideTall, WideShort, ThinTall, ThinShort, None}
// main entry point
public static void Run(IntPtr windowHandle)
{
// for debug string
string output = "";
// get the monitor area
Rectangle monitorRect = BFS.Monitor.GetMonitorWorkAreaByWindow(windowHandle);
// actions are based on the location of the focused window, so go ahead and grab it's borders
Rectangle focusWindowRect = BFS.Window.GetBounds(windowHandle);
// check if the current window is in a corner, if it's not, don't do anything
Quad focusWindowCorner = GetCorner(focusWindowRect, monitorRect);
if (focusWindowCorner == Quad.None)
{
if (debug) BFS.Dialog.ShowMessageInfoMonospaced("Returning due to focus window not in corner");
return;
}
// check if the current window is either a quarter or the defined percentage of the monitor, if it's not, we don't know what percentage to set it to, so abort
bool isQuarter = IsPercentSize(focusWindowRect, monitorRect, 50, 50);
bool isPercent = IsPercentSize(focusWindowRect, monitorRect, percentHeight, percentWidth);
if (!isQuarter && !isPercent)
{
if (debug) BFS.Dialog.ShowMessageInfoMonospaced("Returning due to focus window not quarter or percent");
return;
}
// iterate through all windows, check if they are in a corner and the correct size, then expand or contract as appropriate
IntPtr[] windowHandles = BFS.Window.GetVisibleWindowHandles();
foreach (IntPtr window in windowHandles)
{
// only operate on named windows. In my testing, there were a number of unnamed invisible windows that I didn't want to mess with
if (BFS.Window.GetText(window) == "") continue;
// the rectangle of the current window we're looping through
Rectangle windowRect = BFS.Window.GetBounds(window);
// call the function to figure out which corner this window is in
Quad windowCorner = GetCorner(windowRect, monitorRect);
// if it's not in a corner, don't do anything
if (windowCorner != Quad.None)
{
// based on the corner of the window that was in focus when this script was called, get the size this window should be set to
switch (GetRelation(focusWindowCorner, windowCorner))
{
// this window is the window that was called, or it is in the same corner. If it's a quarter of the screen, expand it to the configured percentage. If it's already at the percentage, move it back to a quarter
case Relative.WideTall:
if (isQuarter)
{
if (IsPercentSize(windowRect, monitorRect, 50, 50)) SetPercentCorner(window, monitorRect, windowCorner, percentWidth, percentHeight);
}
else if (isPercent)
{
if (IsPercentSize(windowRect, monitorRect, percentWidth, percentHeight)) SetPercentCorner(window, monitorRect, windowCorner, 50, 50);
}
break;
// this window is in the opposite corner, so it should be both shorter and thinner to fit
case Relative.ThinShort:
if (isQuarter)
{
if (IsPercentSize(windowRect, monitorRect, 50, 50)) SetPercentCorner(window, monitorRect, windowCorner, 100 - percentWidth, 100 - percentHeight);
}
else if (isPercent)
{
if (IsPercentSize(windowRect, monitorRect, 100 - percentWidth, 100 - percentHeight)) SetPercentCorner(window, monitorRect, windowCorner, 50, 50);
}
break;
// this window was to the right or left of the called window, so it should be thin and tall to fit
case Relative.ThinTall:
if (isQuarter)
{
if (IsPercentSize(windowRect, monitorRect, 50, 50)) SetPercentCorner(window, monitorRect, windowCorner, 100 - percentWidth, percentHeight);
}
else if (isPercent)
{
if (IsPercentSize(windowRect, monitorRect, 100 - percentWidth, percentHeight)) SetPercentCorner(window, monitorRect, windowCorner, 50, 50);
}
break;
// this window was above or below the called window, so it should be wide and short to fit
case Relative.WideShort:
if (isQuarter)
{
if (IsPercentSize(windowRect, monitorRect, 50, 50)) SetPercentCorner(window, monitorRect, windowCorner, percentWidth, 100 - percentHeight);
}
else if (isPercent)
{
if (IsPercentSize(windowRect, monitorRect, percentWidth, 100 - percentHeight)) SetPercentCorner(window, monitorRect, windowCorner, 50, 50);
}
break;
}
// debug string
if (debug)
{
output += string.Format("{0} : {1} : {2} : {3} | {4} | {5} | {6}\n", windowRect.X, windowRect.X + windowRect.Width, windowRect.Y, windowRect.Y + windowRect.Height, windowCorner, IsPercentSize(windowRect, monitorRect, 50, 50), BFS.Window.GetText(window));
}
}
}
// if debug is turned on, print the debug output
if (debug)
{
BFS.Dialog.ShowMessageInfoMonospaced(output);
}
}
// do the multiplications and type conversions to get a number of pixels that are the specified percent of the initial number
public static int GetPercentOf(int initial, int percent)
{
return (int)(initial * ((float)(percent) / 100));
}
// return whether the two quads are in opposite corners
public static bool IsOpposite(Quad original, Quad current)
{
if (original == Quad.TopLeft && current == Quad.BottomRight) return true;
if (original == Quad.BottomLeft && current == Quad.TopRight) return true;
if (original == Quad.TopRight && current == Quad.BottomLeft) return true;
if (original == Quad.BottomRight && current == Quad.TopLeft) return true;
return false;
}
// return whether the quads are directly to the right or left of each other
public static bool IsRightLeft(Quad original, Quad current)
{
if (original == Quad.TopLeft && current == Quad.TopRight) return true;
if (original == Quad.BottomLeft && current == Quad.BottomRight) return true;
if (original == Quad.TopRight && current == Quad.TopLeft) return true;
if (original == Quad.BottomRight && current == Quad.BottomLeft) return true;
return false;
}
// return whether the quads are directly above or below each other
public static bool IsAboveBelow(Quad original, Quad current)
{
if (original == Quad.TopLeft && current == Quad.BottomLeft) return true;
if (original == Quad.BottomLeft && current == Quad.TopLeft) return true;
if (original == Quad.TopRight && current == Quad.BottomRight) return true;
if (original == Quad.BottomRight && current == Quad.TopRight) return true;
return false;
}
// return the relation enum between the current quad the the original focused window's quad
public static Relative GetRelation(Quad original, Quad current)
{
if (original == current) return Relative.WideTall;
if (IsOpposite(original, current)) return Relative.ThinShort;
if (IsRightLeft(original, current)) return Relative.ThinTall;
if (IsAboveBelow(original, current)) return Relative.WideShort;
return Relative.None;
}
// set the given window to the given percentages or the size of the monitor and put it in the given corner
public static void SetPercentCorner(IntPtr window, Rectangle monitor, Quad corner, int percentSizeX, int percentSizeY)
{
switch (corner)
{
case Quad.TopLeft:
BFS.Window.SetSizeAndLocation(window, 0, 0, GetPercentOf(monitor.Width, percentSizeX), GetPercentOf(monitor.Height, percentSizeY));
break;
case Quad.BottomLeft:
BFS.Window.SetSizeAndLocation(window, 0, GetPercentOf(monitor.Height, 100 - percentSizeY), GetPercentOf(monitor.Width, percentSizeX), GetPercentOf(monitor.Height, percentSizeY));
break;
case Quad.TopRight:
BFS.Window.SetSizeAndLocation(window, GetPercentOf(monitor.Width, 100 - percentSizeX), 0, GetPercentOf(monitor.Width, percentSizeX), GetPercentOf(monitor.Height, percentSizeY));
break;
case Quad.BottomRight:
BFS.Window.SetSizeAndLocation(window, GetPercentOf(monitor.Width, 100 - percentSizeX), GetPercentOf(monitor.Height, 100 - percentSizeY), GetPercentOf(monitor.Width, percentSizeX), GetPercentOf(monitor.Height, percentSizeY));
break;
}
}
// return whether or not the given window the the given percentage of the size of the monitor
public static bool IsPercentSize(Rectangle window, Rectangle monitor, int percentSizeX, int percentSizeY)
{
if (IsWithin(window.Width, GetPercentOf(monitor.Width, percentSizeX), tolerence) && IsWithin(window.Height, GetPercentOf(monitor.Height, percentSizeY), tolerence)) return true;
return false;
}
// get the corner that the given window is in, or the None value if it is not in a corner
public static Quad GetCorner(Rectangle window, Rectangle monitor)
{
if (IsWithin(window.X, 0, tolerence))
{
if (IsWithin(window.Y, 0, tolerence))
{
return Quad.TopLeft;
}
else if (IsWithin(window.Y + window.Height, monitor.Height, tolerence))
{
return Quad.BottomLeft;
}
}
else if (IsWithin(window.X + window.Width, monitor.Width, tolerence))
{
if (IsWithin(window.Y, 0, tolerence))
{
return Quad.TopRight;
}
else if (IsWithin(window.Y + window.Height, monitor.Height, tolerence))
{
return Quad.BottomRight;
}
}
return Quad.None;
}
// return whether the target with within the specified tolerence of the initial value
private static bool IsWithin(int value, int target, int threshold)
{
return (value == target) || ((value >= target - threshold) && (value <= target + threshold));
}
}