Processing Ajax...

Title

Message

Confirm

Confirm

Confirm

Confirm

Are you sure you want to delete this item?

Confirm

Are you sure you want to delete this item?

Expand current window from corner and contract other windows to match

Description
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.
Language
C#.net
Minimum Version
Created By
Greg Robertson48861
Contributors
-
Date Created
Mar 14, 2018
Date Last Modified
Mar 14, 2018

Scripted Function (Macro) Code

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));
	}
}