The Omni Group Forums

The Omni Group Forums (http://forums.omnigroup.com/index.php)
-   OmniOutliner 3 for Mac (http://forums.omnigroup.com/forumdisplay.php?f=9)
-   -   Automatically resizing and positioning a OmniOutliner window (http://forums.omnigroup.com/showthread.php?t=19890)

RobTrew 2011-01-26 02:33 AM

Automatically resizing and positioning an OmniOutliner window
 
When I'm working with a single monitor I often have OO3 as a full-height window in the right-hand third of the screen, and some other application in the left-hand two thirds. (Taking notes, or working through some kind of list in OO3).

Here is a script which will resize and reposition the selected window (of any application, as it happens) to the rightmost third of the screen.

Edit the 1st four property values to get the window size and position that you want. (I personally use 3 or 4 of these scripts, with keystrokes assigned to each).

[CODE]-- SET SIZE AND POSITION OF SELECTED WINDOW (ANY APPLICATION)

-- NB:
-- 1. only for single monitor setups
-- 2. Not all windows can be arbitrarily resized )

-- EXAMPLE: A full-height window, rightmost third of the screen:

-- POSITION (origin: top left)
property pPosnAcross : 2 / 3
property pPosnDown : 0

-- SIZE (units: proportion of the desktop)
property pSizeAcross : 1 / 3
property pSizeDown : 1

property pMenuHeight : 22

tell application id "com.apple.finder"
tell window of desktop
set {_, _, lngwidth, lngHeight} to bounds
set lngHeight to lngHeight - pMenuHeight
end tell
end tell

tell application id "com.apple.systemevents"
tell front window of (first application process where frontmost = true)
set position to {pPosnAcross * lngwidth, (pPosnDown * lngHeight) + pMenuHeight}
set size to {pSizeAcross * lngwidth, pSizeDown * lngHeight}
end tell
end tell

[/CODE]

RobTrew 2011-01-27 09:01 AM

FWIW a version which should work with single or multiple display systems, and can be run from the command line with four arguments: [I]OriginX, OriginY, Width, Depth[/I] [and, optionally [I]Index[/I] - see next post].
(Useful for assigning keystrokes to a variety of screen positions with something like Keyboard Maestro).

[CODE]property pVer : "1.2"
property pTitle : "Resize and reposition window by % of screen" & tab & pVer

-- SET SIZE AND POSITION OF SELECTED WINDOW (ANY APPLICATION)
-- (WORKS WITH SINGLE OR DUAL DISPLAY SYSTEMS)

-- Can be also used with arguments from the command line.

-- e.g. if saved as ~/Library/Scripts/PlaceWin.scpt then,
-- to resize the selected window to the left third of the screen:

-- osascript ~/Library/Scripts/PlaceWin.scpt 0 0 0.333 1

-- where the parameters are OriginX OriginY Width Depth

-- THUS, TO RESTORE A WORKSPACE, A COMMAND LINE BATCH SCRIPT LIKE
-- open -a 'omnioutliner professional'
-- osascript ~/Library/Scripts/PlaceWin.scpt 0 0 0.667 1 2
-- open -a 'DEVONthink Pro'
-- osascript ~/Library/Scripts/PlaceWin.scpt 0 0 0.667 1 1

-- (Which can be assigned to a keystroke with something like KeyBoard Maestro)

-- Version history
-- Ver 0.4 Waits, up to pTimeOut seconds, for the frontmost process to present a window (useful if an app is loading)
-- Ver 0.5 Should support more than two monitors. Code has been slightly simplified.
-- Ver 0.7 Cycles between one-corner rectangles, and their left-right and top-down complements
-- Ver 0.8 Accepts a fifth argument: an index which suppresses toggling and selects a particular transform of the basic coordinates (usually 1)
-- (Useful when calling the script after an open -b or open -a to launch an application)
-- Ver 0.9 if the height or width is 0.5 toggles between vertical and horizontal splits
-- (Economises on the allocation of keyboard shortcuts through something like Keyboard Maestro)
-- Ver 1.0 if the height or width is < 0.5 and expressible as 1/N where N is a small integer (≤ 6), then cycles between the N fitting rectangles
-- Ver 1.1 Restores compensation for menu bar space (though Microsoft Word still recalcitrant with landscape splits)
-- Ver 1.2 Defaults to the primary rectangle on the first call with a particular set of parameters
-- (Begins to cycle through any screen-tiling transforms on the first repeated call).

-- DEFAULT: A full-height window, rightmost third of the screen:
-- NB (Not all windows can be arbitrarily resized)

-- UNITS - proportion of whichever screen is displaying the selected window
-- POSITION - (origin: top left)
property pPosnAcross : 0
property pPosnDown : 0

-- SIZE
property pSizeAcross : 1 / 3
property pSizeDown : 1

property pblnMenuWindow : false
property pMenuHeight : 22
property pstrWinPrefsPath : "/Library/Preferences/com.apple.windowserver.plist"
property pTimeout : 10 -- Maximum number of seconds to wait for a loading app to present a window

property plstDisplays : {}
property piBox : 0
property piSpecific : missing value
property pblnRepeat : false

on run argv
-- PROCESS ANY ARGUMENTS PASSED BY AN OSASCRIPT SHELL COMMAND
try
if class of argv is list then
-- FIRST FOUR ARGUMENTS REQUIRED: OriginX, OriginY, Width, Height
set refPosnSize to a reference to items 1 thru 4 of argv
repeat with i from 1 to 4
set item i of refPosnSize to (item i of refPosnSize) as real
end repeat

-- RECORD WHETHER THESE ARGUMENTS MATCH THOSE OF THE PREVIOUS CALL
-- (WE MAY NEED TO CYCLE TO THE NEXT COMPLEMENTARY TRANSFORM)
set pblnRepeat to (contents of refPosnSize) = {pPosnAcross, pPosnDown, pSizeAcross, pSizeDown}

-- AND UPDATE THE PERSISTENT PARAMETERS IF THEY HAVE CHANGED
if not pblnRepeat then set {pPosnAcross, pPosnDown, pSizeAcross, pSizeDown} to refPosnSize

-- HANDLE THE OPTIONAL FIFTH ARGUMENT
-- (AN INDEX TO A SPECIFIC COMPLEMENTARY TRANSFORM (LEFT/RIGHT OR TOP/DOWN) OF THE BASE RECTANGLE)
-- USEFUL IF THE OSASCRIPT CALL FOLLOWS AN OPEN -A CALL
-- WHICH AIMS TO OPEN A NAMED APP TO A SPECIFIC WINDOW SIZE/POSN
if length of argv > 4 then
set piSpecific to (item 5 of argv)
else
set piSpecific to missing value
end if

-- IF THIS IS NOT A REPEATED CALL WITH THE SAME ARGUMENTS,
-- (AND NO TRANSFORM HAS BEEN SPECIFIED),
-- THEN DEFAULT TO THE BASE RECTANGLE (TRANSFORM 1)
if (not pblnRepeat) and (piSpecific is missing value) then set piSpecific to 1
end if
on error strError
return strError
end try

-- NOW REPOSITION AND RESIZE THE FRONT WINDOW,
-- USING THE GIVEN PROPORTIONS OF THE CURRENT SCREEN SIZE
ReSizePosn()
end run

-- GET THE CURRENT SCREEN SIZE,
-- AND MOVE AND RESIZE THE FRONT WINDOW USING PROPORTIONAL DIMENSIONS
on ReSizePosn()
-- GET THE PROPERTIES OF THE REMEMBERED DISPLAYS
tell application id "com.apple.systemevents"
tell contents of property list file pstrWinPrefsPath
set plstDisplays to (first item of ((value of (property list item "DisplaySets")) as list))
end tell

-- GET THE FRONT WINDOW AND ITS POSITION
set refProc to a reference to (first application process where frontmost = true)
set procFront to (first application process where frontmost = true)
set oWin to missing value
repeat with i from 1 to pTimeout * 2
if (count of windows of procFront) > 0 then exit repeat
do shell script "sleep 0.5"
end repeat
set blnMSWord to (name of procFront) contains "Microsoft Word"
set oWin to front window of procFront
if oWin is missing value then return
set {lngWinX, lngWinY} to position of oWin

-- FIND THE DISPLAY CONTAINING THE TOP LEFT CORNER OF THIS WINDOW
set blnFound to false
repeat with recDisplay in plstDisplays
set {lngScreenX, lngScreenY, lngScreenAcross, lngScreenDown} to {OriginX, OriginY, Width, Height} of recDisplay
if ((lngWinX ≥ lngScreenX) and (lngWinX < (lngScreenX + lngScreenAcross)) and ¬
((lngWinY ≥ lngScreenY) and (lngWinY < (lngScreenY + lngScreenDown)))) then
set pblnMenuWindow to {lngScreenX, lngScreenY} = {0, 0}
set blnFound to true
exit repeat
end if
end repeat
if not blnFound then return

set lstBoxes to my GetTransforms({pPosnAcross, pPosnDown, pSizeAcross, pSizeDown}, {lngScreenX, lngScreenY, lngScreenAcross, lngScreenDown})
if piSpecific is missing value then
set piBox to piBox + 1
if piBox > length of lstBoxes then set piBox to 1
else
try
set piBox to (piSpecific as integer) -- specified as fifth argument of the command line
on error
set piBox to 1
end try
end if

set {lngWinX, lngWinY, lngWinWidth, lngWinHeight} to item piBox of lstBoxes
if pblnMenuWindow then set lngWinY to lngWinY + pMenuHeight
tell oWin
if blnMSWord then
tell application id "com.Microsoft.Word"
tell front window of active document
set position to {lngWinX, lngWinY + (pMenuHeight)}
set width to lngWinWidth
set height to lngWinHeight
end tell
end tell
else
set {position, size} to {{lngWinX, lngWinY}, {lngWinWidth, lngWinHeight}}
end if
end tell
end tell
return
end ReSizePosn

-- FOR RECTANGLES WHICH INCLUDE ONE OR TWO CORNERS OF THE SCREEN,
-- OR TOUCH OPPOSITE EDGES OF THE SCREEN, AND HAVE A HEIGHT OR WIDTH
-- WHICH IS A SIMPLE FRACTION OF THE CORRESPONDING SCREEN DIMENSION
-- GENERATE THE SCREEN-TILING SET OF COMPLEMENTARY RECTANGLES.

-- (REPEATED CALLS OF THE SCRIPT WITH THE SAME PARAMETERS CYCLE THROUGH THESE COMPLEMENTARY TRANSFORMS,
-- ALLOWING SIMPLE TILING OF THE SCREEN WITH A SMALL NUMBER OF ASSIGNED KEYSTROKES)
on GetTransforms({pPosnAcross, pPosnDown, pSizeAcross, pSizeDown}, {lngScreenX, lngScreenY, lngScreenAcross, lngScreenDown})
if pblnMenuWindow then
set lngScreenDown to lngScreenDown - pMenuHeight
--set lngScreenY to lngScreenY + pMenuHeight
end if
set {lngX, lngY, lngwidth, lngHeight} to {(pPosnAcross * lngScreenAcross) + lngScreenX, (pPosnDown * lngScreenDown) + lngScreenY, pSizeAcross * lngScreenAcross, pSizeDown * lngScreenDown}
set {pSizeAcross, pSizeDown} to {pSizeAcross as real, pSizeDown as real}

set {lngDeltaX, lngDeltaY} to {0, 0}
if lngX = 0 then set lngDeltaX to lngwidth
if lngY = 0 then set lngDeltaY to lngHeight

if (pSizeAcross = 1.0) or (pSizeDown = 1.0) then -- Single split left/right or up/down
if pSizeAcross = 1.0 then
-- UP DOWN
if pSizeDown = 0.5 then -- (vertical and horizontal splits)
set {lngAltwidth, lngAltHeight} to {pSizeDown * lngScreenAcross, pSizeAcross * lngScreenDown}
{{lngX, lngY, lngwidth, lngHeight}, {lngX, lngDeltaY, lngwidth, lngScreenDown - lngHeight}, ¬
{0, 0, lngAltwidth, lngAltHeight}, {lngAltwidth, 0, lngScreenAcross - lngAltwidth, lngAltHeight}}
else if pSizeDown ≥ (1 / 6) and IsSimpleFraction(pSizeDown) then
set lst to {}
set lngDeltaY to 0
repeat with i from 1 to (1 / pSizeDown) as integer
set end of lst to {lngX, lngDeltaY, lngwidth, lngHeight}
set lngDeltaY to lngDeltaY + lngHeight
end repeat
lst
else
{{lngX, lngY, lngwidth, lngHeight}, {lngX, lngDeltaY, lngwidth, lngScreenDown - lngHeight}}
end if
else
-- LEFT RIGHT
if pSizeAcross = 0.5 then
set {lngAltwidth, lngAltHeight} to {pSizeDown * lngScreenAcross, pSizeAcross * lngScreenDown}
{{lngX, lngY, lngwidth, lngHeight}, {lngDeltaX, lngY, lngScreenAcross - lngwidth, lngHeight}, ¬
{0, 0, lngAltwidth, lngAltHeight}, {0, lngAltHeight, lngAltwidth, lngScreenDown - lngAltHeight}}
else if pSizeAcross ≥ (1 / 6) and IsSimpleFraction(pSizeAcross) then
set lst to {}
set lngDeltaX to 0
repeat with i from 1 to (1 / pSizeAcross) as integer
set end of lst to {lngDeltaX, lngY, lngwidth, lngHeight}
set lngDeltaX to lngDeltaX + lngwidth
end repeat
lst
else
{{lngX, lngY, lngwidth, lngHeight}, {lngDeltaX, lngY, lngScreenAcross - lngwidth, lngHeight}}
end if
end if
else -- does this have at least one corner ? (at {0,0} or (height+y)=1) or ((width+x)=1)
if ({lngX, lngY} = {0, 0}) or AlmostOne(pSizeDown + pPosnDown) or AlmostOne(pSizeAcross + pPosnAcross) then

{{lngX, lngY, lngwidth, lngHeight}, ¬
{lngX, lngDeltaY, lngwidth, lngScreenDown - lngHeight}, ¬
{lngDeltaX, lngDeltaY, lngScreenAcross - lngwidth, lngScreenDown - lngHeight}, ¬
{lngDeltaX, lngY, lngScreenAcross - lngwidth, lngHeight}}
else
{{lngX, lngY, lngwidth, lngHeight}}
end if
end if
end GetTransforms

on AlmostOne(rNumber)
(1 - rNumber) < 0.01
end AlmostOne

on IsSimpleFraction(nNumber)
if nNumber > 0.5 then
return false
else
set n to 1 / nNumber
Abs((n as real) - (n as integer)) < 0.01
end if
end IsSimpleFraction

on Abs(n)
if n < 0 then
-n
else
n
end if
end Abs
[/CODE]

[COLOR="White"]--[/COLOR]

RobTrew 2011-01-28 12:55 AM

Thus to restore a workspace with, for example, OO3 in the right-hand third of the screen, and DevonThink in the left-hand two thirds, you could use a batch of shell commands like this:
[CODE]
#!/bin/sh
open -a 'DEVONthink Pro'
osascript ~/Library/Scripts/PlaceWin.scpt 0 0 0.667 1 1
open -a 'omnioutliner professional'
osascript ~/Library/Scripts/PlaceWin.scpt 0 0 0.667 1 2
[/CODE]

(The fifth argument is an index. Repeated calls with the same parameters make the script cycle through complementary screen-tiling rectangles. Index 1 gives the primary rectangle, Index 2 gives the first complementary tile. In this case the right-hand third of the screen, to fill the screen by complementing the left-hand two thirds.

Automatic cycling through complementary tiles makes it possible to fill the screen quickly using a small number of assigned keystrokes).

( Note that for this to work well you probably need to set your oo3 preference to [I]OmniOutliner > Preferences > General > When OmniOutliner Starts Up > Create a new document[/I] )

A shell script like this can, of course, be assigned to a key-stroke using, for example, FastScripts or Keyboard Maestro.

[COLOR="White"]--[/COLOR]


All times are GMT -8. The time now is 02:26 PM.

Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2024, vBulletin Solutions, Inc.