Hi.
As Marc says, it depends on how much disorder there is. But if all the boxes are at least partially within the rows and columns they’re supposed to be in, and don’t overlap adjacent rows or columns, it’s fairly easy to get a list of them sorted by ‘bounds’. I’ve no idea what app your boxes come from, but the script below uses the bounds of items in an icon-view Finder window to illustrate the method. (It requires this sort as a library script.) You’d just replace the Finder code with the equivalent code for getting the boxes and their bounds from a page in your application.
use AppleScript version "2.3.1" -- Mac OS 10.9 (Mavericks) or later.
use scripting additions
-- This script uses my Custom Iterative Dual-pivot Quicksort <https://macscripter.net/viewtopic.php?pid=192496#p192496>,
-- assumed to have been saved with the name "Custom Iterative Dual-pivot Quicksort.scpt" in ~/Library/Script Libraries/.
use sorter : script "Custom Iterative Dual-pivot Quicksort"
-- Get a list of the items to be sorted (here the items in an icon-view Finder window) and a list of their 'bounds'.
tell application "Finder"
tell items of target of front Finder window
set {theItems, theBoundsLists} to {it, bounds}
end tell
end tell
-- Sort customiser.
-- Bounds list 'a' should go after bounds list 'b' if a's top comes after (below) b's bottom or, failing that, a's bottom comes after b's top (same line) and a's left comes after b's right.
script byBounds
on isGreater(a, b)
set {aLeft, aTop, aRight, aBottom} to a
set {bLeft, bTop, bRight, bBottom} to b
return (aTop comes after bBottom) or ((aBottom comes after bTop) and (aLeft comes after bRight))
end isGreater
end script
-- Sort items 1 thru -1 of the bounds list using the above customiser, rearranging the list of original items in parallel.
tell sorter to sort(theBoundsLists, 1, -1, {comparer:byBounds, slave:{theItems}})
return theItems
If you needed to include the page numbers in the sort, that could be done too. You could perhaps combine the bounds and page numbers into a list of records (eg. {{pageNumber:1, |bounds|:{522, 199, 586, 263}}, … } ) and sort like this:
use AppleScript version "2.3.1" -- Mac OS 10.9 (Mavericks) or later.
use scripting additions
-- This script uses my Custom Iterative Dual-pivot Quicksort <https://macscripter.net/viewtopic.php?pid=192496#p192496>,
-- assumed to have been saved with the name "Custom Iterative Dual-pivot Quicksort.scpt" in ~/Library/Script Libraries/.
use sorter : script "Custom Iterative Dual-pivot Quicksort"
-- Get a list of the items to be sorted (here the items in an icon-view Finder window), a list of their 'bounds', and a list of their page numbers.
tell application "Finder"
tell items of target of front Finder window
set {theItems, theBounds, thePageNumbers} to {it, bounds, {1, 4, 3, 5, 2, 1, 2, 3, 4, 5}} -- Page numbers obviously hard coded for this demo.
end tell
end tell
-- Combine the page numbers and bounds into a list of records, each record containing an item's page number and bounds.
set pageNumbersAndBounds to {}
repeat with i from 1 to (count theItems)
set end of pageNumbersAndBounds to {pageNumber:(item i of thePageNumbers), |bounds|:(item i of theBounds)}
end repeat
-- Sort customiser.
-- Record 'a' should go after record 'b' if (they have the same page number and a's top bound comes after (below) b's bottom or, failing that, a's bottom bound comes after b's top (same line) and a's left comes after b's right) or if a's page number come's after b's page number.
script byPageNumberAndBounds
on isGreater(a, b)
set aPage to a's pageNumber
set bPage to b's pageNumber
if (aPage = bPage) then
set {aLeft, aTop, aRight, aBottom} to a's |bounds|
set {bLeft, bTop, bRight, bBottom} to b's |bounds|
return (aTop comes after bBottom) or ((aBottom comes after bTop) and (aLeft comes after bRight))
else
return (aPage comes after bPage)
end if
end isGreater
end script
-- Sort items 1 thru -1 of the list of records using the above customiser, rearranging the list of original items in parallel.
tell sorter to sort(pageNumbersAndBounds, 1, -1, {comparer:byPageNumberAndBounds, slave:{theItems}})
return theItems