Terminal.appのウィンドウを横方向の間隔でグループ化してグリッドにそろえるスクリプト

このエントリの続き。このままではまだ使いにくいので、もっと賢くしていかないとなあ。

on createOverlappingPair(_first, _second, _xRange)
	script OverlappingPair
		property FirstWindowIndex : _first
		property SecondWindowIndex : _second
		property xRange : _xRange
		to theOtherOneOf(theItem)
			if theItem = SecondWindowIndex then
				return FirstWindowIndex
			else
				return SecondWindowIndex
			end if
		end theOtherOneOf
	end script
	return OverlappingPair
end createOverlappingPair

on calculateOverlappingXRange(theBounds, theBoundsOfAnother)
	if the item 1 of theBounds > the item 3 of theBoundsOfAnother then
		return (the item 3 of theBoundsOfAnother) - (the item 1 of theBounds)
	else if the item 3 of theBounds < the item 1 of theBoundsOfAnother then
		return (the item 3 of theBounds) - (the item 1 of theBoundsOfAnother)
	else if the item 1 of theBounds < the item 3 of theBoundsOfAnother and the item 3 of theBounds > the item 3 of theBoundsOfAnother then
		return (the item 3 of theBoundsOfAnother) - (the item 1 of theBounds)
	else if the item 3 of theBounds > the item 1 of theBoundsOfAnother and the item 3 of theBoundsOfAnother > the item 3 of theBounds then
		return (the item 3 of theBounds) - (the item 1 of theBoundsOfAnother)
	end if
	return 0
end calculateOverlappingXRange

on abs(theValue)
	if theValue < 0 then
		return -theValue
	else
		return theValue
	end if
end abs

tell application "Finder" to set theWorkspaceBounds to the bounds of the window of the desktop
tell application "Terminal"
	set theWindows to {}
	set theBoundsList to {}
	set theNumberOfWindows to (the count of the window) - 1
	if theNumberOfWindows &#8804; 1 then return
	repeat with theWindow in the windows
		if the index of theWindow > theNumberOfWindows ¬
			then exit repeat
		set theWindows to theWindows & {theWindow}
		set theBounds to the bounds of theWindow
		set theBoundsList to theBoundsList & {theBounds}
	end repeat
	
	set theOverlappingPairs to {}
	set theNearestNeighborXRangeList to {}
	set theWindowGroups to {}
	set theWindowGroupIndices to {}
	set theOverlappingXRange to 0
	repeat with theIndex from 1 to (the count of theBoundsList)
		set theMaximumOverlappingXRange to 0
		set theBounds to the item (theIndex) of theBoundsList
		repeat with theAnotherIndex from 1 to the count of theBoundsList
			if theIndex is not theAnotherIndex then
				set theBoundsOfAnother to the item (theAnotherIndex) of theBoundsList
				set theOverlappingXRange to ¬
					me's calculateOverlappingXRange(theBounds, theBoundsOfAnother)
				if theMaximumOverlappingXRange = 0 or ¬
					theOverlappingXRange > theMaximumOverlappingXRange then
					set theMaximumOverlappingXRange to theOverlappingXRange
				end if
				set theOverlappingPairs to theOverlappingPairs & {¬
					me's createOverlappingPair(theIndex, theAnotherIndex, theOverlappingXRange)}
			end if
		end repeat
		set theWindowGroups to theWindowGroups & {{}}
		set theWindowGroupIndices to theWindowGroupIndices & {0}
		
		repeat until (the count of theNearestNeighborXRangeList) &#8805; theIndex
			set theNearestNeighborXRangeList to theNearestNeighborXRangeList & {null}
		end repeat
		set the item (theIndex) of theNearestNeighborXRangeList to theMaximumOverlappingXRange
	end repeat
	
	
	set theRealNumberOfWindowGroups to 0
	set theAverageWidthOfTheWindow to 0
	repeat with theIndex from 1 to the count of theBoundsList
		set unpaired to true
		set theBounds to the item (theIndex) of theBoundsList
		set theNearestNeighborXRange to the item (theIndex) of theNearestNeighborXRangeList
		set theWidthOfTheWindow to the (item 3 of theBounds) - the (item 1 of theBounds)
		set theAverageWidthOfTheWindow to theAverageWidthOfTheWindow + theWidthOfTheWindow
		if theNearestNeighborXRange > theWidthOfTheWindow / 1.5 then
			repeat with thePair in theOverlappingPairs
				if thePair's FirstWindowIndex = theIndex then
					if (me's abs((thePair's xRange) - theNearestNeighborXRange)) / (me's abs(theNearestNeighborXRange / theWidthOfTheWindow)) < theNearestNeighborXRange / 2 then
						set theIndexOfTheOther to thePair's theOtherOneOf(theIndex)
						set theWindowGroupIndex to the item (theIndexOfTheOther) of theWindowGroupIndices
						if theWindowGroupIndex is not theIndex then
							if theWindowGroupIndex is not 0 then
								set the item (theWindowGroupIndex) of theWindowGroups to the item (theWindowGroupIndex) of theWindowGroups & {theIndex}
								set the item (theIndex) of the theWindowGroupIndices to theWindowGroupIndex
							else
								set the item (theIndexOfTheOther) of theWindowGroups to the item (theIndexOfTheOther) of theWindowGroups & {theIndexOfTheOther, theIndex}
								set the item (theIndex) of the theWindowGroupIndices to theIndexOfTheOther
								set theRealNumberOfWindowGroups to theRealNumberOfWindowGroups + 1
							end if
						end if
						set unpaired to false
					end if
				end if
			end repeat
		end if
		if unpaired then
			set the item (theIndex) of theWindowGroups to the item (theIndex) of theWindowGroups & {theIndex}
			set the item (theIndex) of the theWindowGroupIndices to theIndex
			set theRealNumberOfWindowGroups to theRealNumberOfWindowGroups + 1
		end if
	end repeat
	set theAverageWidthOfTheWindow to theAverageWidthOfTheWindow / the (count of theBoundsList)
	set theGridWidth to (the (item 3 of theWorkspaceBounds) - the (item 1 of theWorkspaceBounds) - theAverageWidthOfTheWindow) / theRealNumberOfWindowGroups
	repeat with theGroup in theWindowGroups
		if the (count of theGroup) > 0 then
			set theBounds to the item (the first item of theGroup) of theBoundsList
			set theWidthOfTheWindow to the (item 3 of theBounds) - (the item 1 of theBounds)
			set theGridIndex to (((the item 1 of theBounds) - (the item 1 of theWorkspaceBounds)) + theGridWidth / 2 - 1) div theGridWidth
			repeat with theWindowIndex in theGroup
				set theWindow to the item (theWindowIndex) of theWindows
				set thePosition to the position of theWindow
				set the item 1 of thePosition to theGridWidth * theGridIndex + the (item 1 of theWorkspaceBounds)
				set the position of theWindow to thePosition
			end repeat
		end if
	end repeat
end tell