Copy link to clipboard
Copied
Hello, I am struggling to make this incorportate units say if a user types 20px or 30pt or 60cm etc
Also it spits out an xml file to the document folder from which it can read past settings a user inputed, this would need to also read say 20px et
Help on this would be most useful
Best
Smyth
/**
* Illustrator Margins, Grid & Baseline Script [Mac-Ready]
* No ES6 code—fully ExtendScript compatible. Tested on Mac.
*/
var settingsXMLPath = Folder.myDocuments + "/IllustratorGridSettings.xml";
// --- XML functions ---
function loadSettingsFromXML(xmlFilePath, abIdx, defaults) {
var file = new File(xmlFilePath);
if (!file.exists) return defaults;
file.open('r');
var content = file.read();
file.close();
var abTag = new RegExp('<Artboard index="' + abIdx + '">([\\s\\S]*?)<\\/Artboard>');
var found = content.match(abTag);
if (found) {
var vals = {};
var tags = ["Top","Bottom","Left","Right","Columns","Rows","VertGutter","HorGutter","BaselineStart","BaselineInc"];
for (var i=0;i<tags.length;i++) {
var tag = new RegExp('<'+tags[i]+'>((.|\\n|\\r)*?)<\\/'+tags[i]+'>');
var t = found[1].match(tag);
vals[tags[i]] = t ? parseFloat(t[1]) : defaults[tags[i]];
}
return vals;
}
return defaults;
}
function saveSettingsToXML(xmlFilePath, abIdx, newVals) {
var file = new File(xmlFilePath);
var xmlContent = '';
if (file.exists) {
file.open('r');
xmlContent = file.read();
file.close();
}
var abTag = new RegExp('<Artboard index="' + abIdx + '">([\\s\\S]*?)<\\/Artboard>','g');
xmlContent = xmlContent.replace(abTag, '');
var abXML = ' <Artboard index="' + abIdx + '">\n';
for (var key in newVals) {
abXML += ' <' + key + '>' + newVals[key] + '</' + key + '>\n';
}
abXML += ' </Artboard>\n';
if (xmlContent.indexOf('<GridSettings>') === -1) {
xmlContent = '<GridSettings>\n' + abXML + '</GridSettings>';
} else {
xmlContent = xmlContent.replace('</GridSettings>', abXML + '</GridSettings>');
}
file.open('w');
file.write(xmlContent);
file.close();
}
// --- Helpers ---
function mmToPt(mm) { return mm * 2.83465; }
function ptToMm(pt) { return pt / 2.83465; }
function makeRGB(r, g, b) {
var color = new RGBColor();
color.red = r; color.green = g; color.blue = b;
return color;
}
function findLayer(doc, name) {
for (var i = 0; i < doc.layers.length; i++) {
if (doc.layers[i].name === name) return doc.layers[i];
}
return null;
}
function deleteLayerByExactName(doc, name) {
for (var i = doc.layers.length - 1; i >= 0; i--) {
if (doc.layers[i].name === name) {
doc.layers[i].locked = false;
doc.layers[i].visible = true;
doc.layers[i].remove();
}
}
}
function removePathsForArtboard(layer, abIdx) {
var abTag = " ab" + abIdx + " ";
for (var i = layer.pathItems.length - 1; i >= 0; i--) {
var p = layer.pathItems[i];
if (p.note && p.note.indexOf(abTag) === 0) p.remove();
}
}
// --- Guide Creation (with per-artboard tagging for merged layers) ---
function addMarginsAndColumnsToLayer(layer, ab, abIdx, top_mm, bottom_mm, left_mm, right_mm, columns, vertGutter_mm, rows, horGutter_mm) {
var rect = ab.artboardRect;
var left = rect[0], top = rect[1], right = rect[2], bottom = rect[3];
var width = right - left, height = top - bottom;
var top_pt = mmToPt(top_mm), bottom_pt = mmToPt(bottom_mm), left_pt = mmToPt(left_mm), right_pt = mmToPt(right_mm);
var vertGutter_pt = mmToPt(vertGutter_mm), horGutter_pt = mmToPt(horGutter_mm);
var abTag = " ab" + abIdx + " ";
// Margin rectangle
var path = layer.pathItems.rectangle(
top - top_pt,
left + left_pt,
width - left_pt - right_pt,
height - top_pt - bottom_pt
);
path.stroked = true;
path.strokeColor = makeRGB(224, 0, 255);
path.strokeWidth = 0.1;
path.filled = false;
path.guides = true;
path.note = abTag + "margin";
// Columns as guides
var gridColor = makeRGB(0, 176, 255);
if (columns > 1) {
var usableWidth = width - left_pt - right_pt;
var colWidth = (usableWidth - (columns - 1) * vertGutter_pt) / columns;
var x = left + left_pt;
for (var c = 0; c < columns - 1; c++) {
x += colWidth;
var vGuide1 = layer.pathItems.add();
vGuide1.setEntirePath([[x, top - top_pt], [x, bottom + bottom_pt]]);
vGuide1.stroked = true; vGuide1.strokeColor = gridColor; vGuide1.strokeWidth = 0.1; vGuide1.filled = false;
vGuide1.guides = true;
vGuide1.note = abTag + "colg";
x += vertGutter_pt;
var vGuide2 = layer.pathItems.add();
vGuide2.setEntirePath([[x, top - top_pt], [x, bottom + bottom_pt]]);
vGuide2.stroked = true; vGuide2.strokeColor = gridColor; vGuide2.strokeWidth = 0.1; vGuide2.filled = false;
vGuide2.guides = true;
vGuide2.note = abTag + "colg";
}
}
// Rows as guides
if (rows > 1) {
var usableHeight = height - top_pt - bottom_pt;
var rowHeight = (usableHeight - (rows - 1) * horGutter_pt) / rows;
var y = top - top_pt;
for (var r = 0; r < rows - 1; r++) {
y -= rowHeight;
var hGuide1 = layer.pathItems.add();
hGuide1.setEntirePath([[left + left_pt, y], [right - right_pt, y]]);
hGuide1.stroked = true; hGuide1.strokeColor = gridColor; hGuide1.strokeWidth = 0.1; hGuide1.filled = false;
hGuide1.guides = true; hGuide1.note = abTag + "rowg";
y -= horGutter_pt;
var hGuide2 = layer.pathItems.add();
hGuide2.setEntirePath([[left + left_pt, y], [right - right_pt, y]]);
hGuide2.stroked = true; hGuide2.strokeColor = gridColor; hGuide2.strokeWidth = 0.1; hGuide2.filled = false;
hGuide2.guides = true; hGuide2.note = abTag + "rowg";
}
}
}
function addBaselineGridToLayer(layer, ab, abIdx, top_mm, bottom_mm, left_mm, right_mm, baselineStart_mm, baselineInc_pt) {
var rect = ab.artboardRect;
var left = rect[0], top = rect[1], right = rect[2], bottom = rect[3];
var top_pt = mmToPt(top_mm), bottom_pt = mmToPt(bottom_mm), left_pt = mmToPt(left_mm), right_pt = mmToPt(right_mm);
var baselineStart_pt = mmToPt(baselineStart_mm);
var abTag = " ab" + abIdx + " ";
var y0 = top - top_pt - baselineStart_pt;
var yEnd = bottom + bottom_pt;
while (y0 > yEnd) {
var line = layer.pathItems.add();
line.setEntirePath([[left + left_pt, y0], [right - right_pt, y0]]);
line.stroked = true;
line.strokeColor = makeRGB(80, 80, 80);
line.strokeWidth = 0.05;
line.filled = false;
line.guides = true;
line.note = abTag + "baseline";
y0 -= baselineInc_pt;
}
}
// --- UI Dialog (always merged mode) ---
function showMarginsDialog() {
if (app.documents.length === 0) { alert("Please open a document first."); return; }
var doc = app.activeDocument;
var abIdx = doc.artboards.getActiveArtboardIndex();
var defaults = {
Top:12.7, Bottom:12.7, Left:12.7, Right:12.7, Columns:2, Rows:2,
VertGutter:4.233, HorGutter:4.233, BaselineStart:0, BaselineInc:12
};
var settings = loadSettingsFromXML(settingsXMLPath, abIdx, defaults);
var w = new Window("dialog", "Margins, Grid & Baseline (for Artboard " + (abIdx + 1) + ")");
w.orientation = "column";
w.alignChildren = "left";
w.spacing = 10;
var marginPanel = w.add("panel", undefined, "Margins (mm)");
marginPanel.orientation = "column";
marginPanel.alignChildren = "left";
marginPanel.margins = 12;
var mRow1 = marginPanel.add("group");
mRow1.orientation = "row";
mRow1.alignChildren = "center";
mRow1.add("statictext", undefined, "Top:");
var topInput = mRow1.add("edittext", undefined, settings.Top);
topInput.characters = 5;
mRow1.add("statictext", undefined, "mm Left:");
var leftInput = mRow1.add("edittext", undefined, settings.Left);
leftInput.characters = 5;
mRow1.add("statictext", undefined, "mm");
var mRow2 = marginPanel.add("group");
mRow2.orientation = "row";
mRow2.alignChildren = "center";
mRow2.add("statictext", undefined, "Bottom:");
var bottomInput = mRow2.add("edittext", undefined, settings.Bottom);
bottomInput.characters = 5;
mRow2.add("statictext", undefined, "mm Right:");
var rightInput = mRow2.add("edittext", undefined, settings.Right);
rightInput.characters = 5;
mRow2.add("statictext", undefined, "mm");
var gridPanel = w.add("panel", undefined, "Grid");
gridPanel.orientation = "row";
gridPanel.alignChildren = "center";
gridPanel.margins = 12;
gridPanel.spacing = 10;
gridPanel.add("statictext", undefined, "Columns:");
var colInput = gridPanel.add("edittext", undefined, settings.Columns);
colInput.characters = 3;
gridPanel.add("statictext", undefined, "Vertical Gutter:");
var vertGutterInput = gridPanel.add("edittext", undefined, settings.VertGutter);
vertGutterInput.characters = 5;
gridPanel.add("statictext", undefined, "mm");
gridPanel.add("statictext", undefined, "Rows:");
var rowInput = gridPanel.add("edittext", undefined, settings.Rows);
rowInput.characters = 3;
gridPanel.add("statictext", undefined, "Horizontal Gutter:");
var horGutterInput = gridPanel.add("edittext", undefined, settings.HorGutter);
horGutterInput.characters = 5;
gridPanel.add("statictext", undefined, "mm");
var basePanel = w.add("panel", undefined, "Baseline Grid");
basePanel.orientation = "row";
basePanel.alignChildren = "center";
basePanel.margins = 12;
basePanel.spacing = 10;
basePanel.add("statictext", undefined, "Start:");
var baselineStartInput = basePanel.add("edittext", undefined, settings.BaselineStart);
baselineStartInput.characters = 5;
basePanel.add("statictext", undefined, "mm Increment:");
var baselineIncInput = basePanel.add("edittext", undefined, settings.BaselineInc);
baselineIncInput.characters = 5;
basePanel.add("statictext", undefined, "pt");
var applyAllGroup = w.add("group");
applyAllGroup.orientation = "row";
var applyAllChk = applyAllGroup.add("checkbox", undefined, "Apply to all artboards");
applyAllChk.value = (doc.artboards.length === 1);
var btnGroup = w.add("group");
btnGroup.orientation = "row";
btnGroup.alignment = "right";
btnGroup.add("button", undefined, "Cancel", { name: "cancel" });
var okBtn = btnGroup.add("button", undefined, "OK", { name: "ok" });
okBtn.onClick = function() {
var top = parseFloat(topInput.text), bottom = parseFloat(bottomInput.text),
leftVal = parseFloat(leftInput.text), rightVal = parseFloat(rightInput.text),
cols = parseInt(colInput.text), rows = parseInt(rowInput.text),
vertGutter = parseFloat(vertGutterInput.text), horGutter = parseFloat(horGutterInput.text),
baselineStart = parseFloat(baselineStartInput.text), baselineInc = parseFloat(baselineIncInput.text);
if (
isNaN(top) || isNaN(bottom) || isNaN(leftVal) || isNaN(rightVal) ||
isNaN(cols) || isNaN(rows) ||
isNaN(vertGutter) || isNaN(horGutter) ||
isNaN(baselineStart) || isNaN(baselineInc) ||
top < 0 || bottom < 0 || leftVal < 0 || rightVal < 0 ||
cols < 0 || rows < 0 ||
vertGutter < 0 || horGutter < 0 ||
baselineInc <= 0
) {
alert("Please enter valid (positive) numbers. Columns and Rows and gutters can be 0 or more, Increment > 0.");
return;
}
function checkGridFit(abIdx, top, bottom, leftVal, rightVal, cols, rows, vertGutter, horGutter) {
var rect = doc.artboards[abIdx].artboardRect;
var artboardW = rect[2] - rect[0] - mmToPt(leftVal) - mmToPt(rightVal);
var artboardHmm = rect[1] - rect[3] - mmToPt(top) - mmToPt(bottom);
var mmW = ptToMm(artboardW), mmH = ptToMm(artboardHmm);
var minColWidth = 1, minRowHeight = 1;
var failCol = false, failRow = false;
if (cols > 1) {
var totalColGutters = (cols - 1) * vertGutter;
var usable = mmW - totalColGutters;
if (usable <= 0 || (usable/cols) < minColWidth) { failCol = true; }
}
if (rows > 1) {
var totalRowGutters = (rows - 1) * horGutter;
var usable = mmH - totalRowGutters;
if (usable <= 0 || (usable/rows) < minRowHeight) { failRow = true; }
}
return {failCol: failCol, failRow: failRow};
}
var abIndices = [];
if (applyAllChk.value) {
for (var i = 0; i < doc.artboards.length; i++) abIndices.push(i);
} else {
abIndices.push(abIdx);
}
var vertGutterOverride = {}, horGutterOverride = {};
var warnedCol = false, warnedRow = false;
for (var i=0; i<abIndices.length; i++) {
var check = checkGridFit(abIndices[i], top, bottom, leftVal, rightVal, cols, rows, vertGutter, horGutter);
if (check.failCol) {
if (!warnedCol) alert("Your column/gutter combination cannot fit on at least one artboard. Vertical gutter is being reset to the default.");
vertGutterOverride[abIndices[i]] = defaults.VertGutter;
warnedCol = true;
}
if (check.failRow) {
if (!warnedRow) alert("Your row/gutter combination cannot fit on at least one artboard. Horizontal gutter is being reset to the default.");
horGutterOverride[abIndices[i]] = defaults.HorGutter;
warnedRow = true;
}
}
// --- Always merge guides into single layers ---
if (applyAllChk.value) {
deleteLayerByExactName(doc, "Margins and Columns");
deleteLayerByExactName(doc, "Baseline");
}
var marginsLayer = findLayer(doc, "Margins and Columns");
if (!marginsLayer) { marginsLayer = doc.layers.add(); marginsLayer.name = "Margins and Columns"; }
marginsLayer.locked = false; marginsLayer.visible = true;
var baselineLayer = findLayer(doc, "Baseline");
if (!baselineLayer) { baselineLayer = doc.layers.add(); baselineLayer.name = "Baseline"; }
baselineLayer.locked = false; baselineLayer.visible = true;
for (var k = 0; k < abIndices.length; k++) {
var idx = abIndices[k];
var thisVertGutter = vertGutterOverride[idx] !== undefined ? vertGutterOverride[idx] : vertGutter;
var thisHorGutter = horGutterOverride[idx] !== undefined ? horGutterOverride[idx] : horGutter;
var ab = doc.artboards[idx];
if (applyAllChk.value) {
// Already wiped, so no selective deletion required
} else {
removePathsForArtboard(marginsLayer, idx);
removePathsForArtboard(baselineLayer, idx);
}
addMarginsAndColumnsToLayer(marginsLayer, ab, idx, top, bottom, leftVal, rightVal, cols, thisVertGutter, rows, thisHorGutter);
addBaselineGridToLayer(baselineLayer, ab, idx, top, bottom, leftVal, rightVal, baselineStart, baselineInc);
saveSettingsToXML(settingsXMLPath, idx, {
Top: top, Bottom: bottom, Left: leftVal, Right: rightVal,
Columns: cols, Rows: rows, VertGutter: thisVertGutter, HorGutter: thisHorGutter,
BaselineStart: baselineStart, BaselineInc: baselineInc
});
}
marginsLayer.locked = true; baselineLayer.locked = true;
w.close();
};
w.center(); w.show();
}
showMarginsDialog();
Copy link to clipboard
Copied
UnitValue can be used for unit conversion. For detailed usage, refer to JavaScript Tools Guide.pdf.
var ptValue = new UnitValue(10, 'mm').as('pt') ;
alert(ptValue) ;
This may be unnecessary advice, but ExtendScript can parse XML and search with XPath, so it may be easier than using regular expressions.
Copy link to clipboard
Copied
Ah okay,
I ended up getting to here
/**
* Illustrator Margins, Grid & Baseline Script [Mac-Ready]
* No ES6 code—fully ExtendScript compatible. Tested on Mac.
*/
var settingsXMLPath = Folder.myDocuments + "/IllustratorGridSettings.xml";
// --- XML functions (Modified to handle raw string values) ---
function loadSettingsFromXML(xmlFilePath, abIdx, defaults) {
// Helper to convert default numbers to strings with units
function stringifyDefaults(defaultsObj) {
var stringDefaults = {};
for (var key in defaultsObj) {
if (defaultsObj.hasOwnProperty(key)) {
if (key === "BaselineInc") {
// Baseline increment defaults to points
stringDefaults[key] = defaultsObj[key].toString() + "pt";
} else if (key === "Columns" || key === "Rows") {
// Numbers only, no units
stringDefaults[key] = defaultsObj[key].toString();
} else {
// Everything else defaults to mm
stringDefaults[key] = defaultsObj[key].toString() + "mm";
}
}
}
return stringDefaults;
}
var file = new File(xmlFilePath);
if (!file.exists) return stringifyDefaults(defaults);
file.open('r');
var content = file.read();
file.close();
var abTag = new RegExp('<Artboard index="' + abIdx + '">([\\s\\S]*?)<\\/Artboard>');
var found = content.match(abTag);
if (found) {
var vals = {};
var tags = ["Top","Bottom","Left","Right","Columns","Rows","VertGutter","HorGutter","BaselineStart","BaselineInc"];
for (var i = 0; i < tags.length; i++) {
var tagName = tags[i];
var tagRegex = new RegExp('<' + tagName + '>([\\s\\S]*?)<\\/' + tagName + '>');
var tagMatch = found[1].match(tagRegex);
if (tagMatch) {
vals[tagName] = tagMatch[1];
} else {
// Apply default with appropriate unit
if (tagName === "BaselineInc") {
vals[tagName] = defaults[tagName].toString() + "pt";
} else if (tagName === "Columns" || tagName === "Rows") {
vals[tagName] = defaults[tagName].toString();
} else {
vals[tagName] = defaults[tagName].toString() + "mm";
}
}
}
return vals;
}
return stringifyDefaults(defaults);
}
function saveSettingsToXML(xmlFilePath, abIdx, newVals) {
var file = new File(xmlFilePath);
var xmlContent = '';
if (file.exists) {
file.open('r');
xmlContent = file.read();
file.close();
}
var abTag = new RegExp('<Artboard index="' + abIdx + '">([\\s\\S]*?)<\\/Artboard>','g');
xmlContent = xmlContent.replace(abTag, '');
var abXML = ' <Artboard index="' + abIdx + '">\n';
for (var key in newVals) {
var value = newVals[key].toString().replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
abXML += ' <' + key + '>' + value + '</' + key + '>\n';
}
abXML += ' </Artboard>\n';
if (xmlContent.indexOf('<GridSettings>') === -1) {
xmlContent = '<GridSettings>\n' + abXML + '</GridSettings>';
} else {
xmlContent = xmlContent.replace('</GridSettings>', abXML + '</GridSettings>');
}
file.open('w');
file.write(xmlContent);
file.close();
}
// --- Helpers ---
function mmToPt(mm) { return mm * 2.83465; }
function ptToMm(pt) { return pt / 2.83465; }
function makeRGB(r, g, b) {
var color = new RGBColor();
color.red = r; color.green = g; color.blue = b;
return color;
}
function findLayer(doc, name) {
for (var i = 0; i < doc.layers.length; i++) {
if (doc.layers[i].name === name) return doc.layers[i];
}
return null;
}
function deleteLayerByExactName(doc, name) {
for (var i = doc.layers.length - 1; i >= 0; i--) {
if (doc.layers[i].name === name) {
doc.layers[i].locked = false;
doc.layers[i].visible = true;
doc.layers[i].remove();
}
}
}
function removePathsForArtboard(layer, abIdx) {
var abTag = " ab" + abIdx + " ";
for (var i = layer.pathItems.length - 1; i >= 0; i--) {
var p = layer.pathItems[i];
if (p.note && p.note.indexOf(abTag) === 0) p.remove();
}
}
// --- Enhanced Unit Parsing Functions with Default Unit Addition ---
function parseValueWithUnit(inputStr) {
if (typeof inputStr !== 'string') {
inputStr = String(inputStr);
}
inputStr = inputStr.replace(/\s/g, '');
var match = inputStr.match(/^(-?\d*\.?\d+)([a-zA-Z%]*)$/);
if (!match) {
var num = parseFloat(inputStr);
return isNaN(num) ? NaN : mmToPt(num);
}
var value = parseFloat(match[1]);
var unit = match[2].toLowerCase();
if (isNaN(value)) return NaN;
switch (unit) {
case '':
case 'mm':
return mmToPt(value);
case 'cm':
return mmToPt(value * 10);
case 'in':
case 'inch':
return value * 72;
case 'pt':
case 'point':
return value;
case 'px':
case 'pixel':
var doc = app.activeDocument;
if (doc.rulerUnits == RulerUnits.Pixels) {
return value;
} else {
return value * 0.75;
}
case 'pc':
case 'pica':
return value * 12;
default:
return mmToPt(value);
}
}
function parseValueWithUnitPt(inputStr) {
return parseValueWithUnit(inputStr);
}
// --- Helper function to add default units to user input ---
function addDefaultUnit(inputStr, fieldType) {
if (typeof inputStr !== 'string') {
inputStr = String(inputStr);
}
inputStr = inputStr.replace(/\s/g, '');
var match = inputStr.match(/^(-?\d*\.?\d+)([a-zA-Z%]*)$/);
if (match && match[2] === '') {
// No unit specified, add appropriate default
if (fieldType === "baseline") {
return inputStr + "pt";
} else if (fieldType === "number") {
return inputStr; // Columns/Rows don't need units
} else {
return inputStr + "mm"; // Default for margins and gutters
}
}
// Unit already specified or invalid input, return as-is
return inputStr;
}
// --- Guide Creation (works directly with points) ---
function addMarginsAndColumnsToLayer(layer, ab, abIdx, top_pt, bottom_pt, left_pt, right_pt, columns, vertGutter_pt, rows, horGutter_pt) {
var rect = ab.artboardRect;
var left = rect[0], top = rect[1], right = rect[2], bottom = rect[3];
var width = right - left, height = top - bottom;
var abTag = " ab" + abIdx + " ";
var path = layer.pathItems.rectangle(top - top_pt, left + left_pt, width - left_pt - right_pt, height - top_pt - bottom_pt);
path.stroked = true; path.strokeColor = makeRGB(224, 0, 255); path.strokeWidth = 0.1; path.filled = false; path.guides = true; path.note = abTag + "margin";
var gridColor = makeRGB(0, 176, 255);
if (columns > 1) {
var usableWidth = width - left_pt - right_pt;
var colWidth = (usableWidth - (columns - 1) * vertGutter_pt) / columns;
var x = left + left_pt;
for (var c = 0; c < columns - 1; c++) {
x += colWidth;
var vGuide1 = layer.pathItems.add();
vGuide1.setEntirePath([[x, top - top_pt], [x, bottom + bottom_pt]]);
vGuide1.stroked = true; vGuide1.strokeColor = gridColor; vGuide1.strokeWidth = 0.1; vGuide1.filled = false; vGuide1.guides = true; vGuide1.note = abTag + "colg";
x += vertGutter_pt;
var vGuide2 = layer.pathItems.add();
vGuide2.setEntirePath([[x, top - top_pt], [x, bottom + bottom_pt]]);
vGuide2.stroked = true; vGuide2.strokeColor = gridColor; vGuide2.strokeWidth = 0.1; vGuide2.filled = false; vGuide2.guides = true; vGuide2.note = abTag + "colg";
}
}
if (rows > 1) {
var usableHeight = height - top_pt - bottom_pt;
var rowHeight = (usableHeight - (rows - 1) * horGutter_pt) / rows;
var y = top - top_pt;
for (var r = 0; r < rows - 1; r++) {
y -= rowHeight;
var hGuide1 = layer.pathItems.add();
hGuide1.setEntirePath([[left + left_pt, y], [right - right_pt, y]]);
hGuide1.stroked = true; hGuide1.strokeColor = gridColor; hGuide1.strokeWidth = 0.1; hGuide1.filled = false; hGuide1.guides = true; hGuide1.note = abTag + "rowg";
y -= horGutter_pt;
var hGuide2 = layer.pathItems.add();
hGuide2.setEntirePath([[left + left_pt, y], [right - right_pt, y]]);
hGuide2.stroked = true; hGuide2.strokeColor = gridColor; hGuide2.strokeWidth = 0.1; hGuide2.filled = false; hGuide2.guides = true; hGuide2.note = abTag + "rowg";
}
}
}
// --- ENHANCED: Baseline Grid Creation (now handles 0 increment gracefully) ---
function addBaselineGridToLayer(layer, ab, abIdx, top_pt, bottom_pt, left_pt, right_pt, baselineStart_pt, baselineInc_pt) {
// If baseline increment is 0, skip creating baseline guides entirely
if (baselineInc_pt <= 0) {
return; // Exit function without creating any baseline guides
}
var rect = ab.artboardRect;
var left = rect[0], top = rect[1], right = rect[2], bottom = rect[3];
var abTag = " ab" + abIdx + " ";
var y0 = top - top_pt - baselineStart_pt;
var yEnd = bottom + bottom_pt;
while (y0 > yEnd) {
var line = layer.pathItems.add();
line.setEntirePath([[left + left_pt, y0], [right - right_pt, y0]]);
line.stroked = true; line.strokeColor = makeRGB(80, 80, 80); line.strokeWidth = 0.05; line.filled = false; line.guides = true; line.note = abTag + "baseline";
y0 -= baselineInc_pt;
}
}
// --- UI Dialog (IMPROVED LAYOUT) ---
function showMarginsDialog() {
if (app.documents.length === 0) { alert("Please open a document first."); return; }
var doc = app.activeDocument;
var abIdx = doc.artboards.getActiveArtboardIndex();
var defaults = {
Top:12.7, Bottom:12.7, Left:12.7, Right:12.7, Columns:2, Rows:2,
VertGutter:4.233, HorGutter:4.233, BaselineStart:0, BaselineInc:12
};
var settings = loadSettingsFromXML(settingsXMLPath, abIdx, defaults);
// Create a wider dialog with better spacing
var w = new Window("dialog", "Margins, Grid & Baseline (for Artboard " + (abIdx + 1) + ")");
w.orientation = "column";
w.alignChildren = "fill";
w.spacing = 15;
w.margins = 20;
// MARGINS PANEL - wider layout with more space
var marginPanel = w.add("panel", undefined, "Margins");
marginPanel.orientation = "column";
marginPanel.alignChildren = "fill";
marginPanel.margins = 15;
marginPanel.spacing = 10;
var mRow1 = marginPanel.add("group");
mRow1.orientation = "row";
mRow1.alignChildren = "center";
mRow1.spacing = 10;
mRow1.add("statictext", undefined, "Top:").preferredSize.width = 60;
var topInput = mRow1.add("edittext", undefined, settings.Top);
topInput.preferredSize.width = 80;
mRow1.add("statictext", undefined, "Left:").preferredSize.width = 60;
var leftInput = mRow1.add("edittext", undefined, settings.Left);
leftInput.preferredSize.width = 80;
var mRow2 = marginPanel.add("group");
mRow2.orientation = "row";
mRow2.alignChildren = "center";
mRow2.spacing = 10;
mRow2.add("statictext", undefined, "Bottom:").preferredSize.width = 60;
var bottomInput = mRow2.add("edittext", undefined, settings.Bottom);
bottomInput.preferredSize.width = 80;
mRow2.add("statictext", undefined, "Right:").preferredSize.width = 60;
var rightInput = mRow2.add("edittext", undefined, settings.Right);
rightInput.preferredSize.width = 80;
// GRID PANEL - better organized layout
var gridPanel = w.add("panel", undefined, "Grid");
gridPanel.orientation = "column";
gridPanel.alignChildren = "fill";
gridPanel.margins = 15;
gridPanel.spacing = 10;
var gRow1 = gridPanel.add("group");
gRow1.orientation = "row";
gRow1.alignChildren = "center";
gRow1.spacing = 10;
gRow1.add("statictext", undefined, "Columns:").preferredSize.width = 80;
var colInput = gRow1.add("edittext", undefined, settings.Columns);
colInput.preferredSize.width = 60;
gRow1.add("statictext", undefined, "Vertical Gutter:").preferredSize.width = 100;
var vertGutterInput = gRow1.add("edittext", undefined, settings.VertGutter);
vertGutterInput.preferredSize.width = 80;
var gRow2 = gridPanel.add("group");
gRow2.orientation = "row";
gRow2.alignChildren = "center";
gRow2.spacing = 10;
gRow2.add("statictext", undefined, "Rows:").preferredSize.width = 80;
var rowInput = gRow2.add("edittext", undefined, settings.Rows);
rowInput.preferredSize.width = 60;
gRow2.add("statictext", undefined, "Horizontal Gutter:").preferredSize.width = 100;
var horGutterInput = gRow2.add("edittext", undefined, settings.HorGutter);
horGutterInput.preferredSize.width = 80;
// BASELINE PANEL - cleaner layout
var basePanel = w.add("panel", undefined, "Baseline Grid");
basePanel.orientation = "row";
basePanel.alignChildren = "center";
basePanel.margins = 15;
basePanel.spacing = 10;
basePanel.add("statictext", undefined, "Start:").preferredSize.width = 80;
var baselineStartInput = basePanel.add("edittext", undefined, settings.BaselineStart);
baselineStartInput.preferredSize.width = 80;
basePanel.add("statictext", undefined, "Increment:").preferredSize.width = 80;
var baselineIncInput = basePanel.add("edittext", undefined, settings.BaselineInc);
baselineIncInput.preferredSize.width = 80;
// APPLY TO ALL CHECKBOX
var applyAllGroup = w.add("group");
applyAllGroup.margins = [0, 10, 0, 0];
var applyAllChk = applyAllGroup.add("checkbox", undefined, "Apply to all artboards");
applyAllChk.value = (doc.artboards.length === 1);
// BUTTONS - better spacing
var btnGroup = w.add("group");
btnGroup.orientation = "row";
btnGroup.alignment = "right";
btnGroup.spacing = 10;
btnGroup.margins = [0, 15, 0, 0];
var cancelBtn = btnGroup.add("button", undefined, "Cancel", { name: "cancel" });
var okBtn = btnGroup.add("button", undefined, "OK", { name: "ok" });
cancelBtn.preferredSize.width = 80;
okBtn.preferredSize.width = 80;
okBtn.onClick = function() {
var top_pt = parseValueWithUnit(topInput.text), bottom_pt = parseValueWithUnit(bottomInput.text),
left_pt = parseValueWithUnit(leftInput.text), right_pt = parseValueWithUnit(rightInput.text),
cols = parseInt(colInput.text), rows = parseInt(rowInput.text),
vertGutter_pt = parseValueWithUnit(vertGutterInput.text), horGutter_pt = parseValueWithUnit(horGutterInput.text),
baselineStart_pt = parseValueWithUnit(baselineStartInput.text), baselineInc_pt = parseValueWithUnitPt(baselineIncInput.text);
// --- ENHANCED VALIDATION: Allow 0 for baseline increment ---
if (isNaN(top_pt) || isNaN(bottom_pt) || isNaN(left_pt) || isNaN(right_pt) ||
isNaN(cols) || isNaN(rows) ||
isNaN(vertGutter_pt) || isNaN(horGutter_pt) ||
isNaN(baselineStart_pt) || isNaN(baselineInc_pt) ||
top_pt < 0 || bottom_pt < 0 || left_pt < 0 || right_pt < 0 ||
cols < 0 || rows < 0 ||
vertGutter_pt < 0 || horGutter_pt < 0 ||
baselineInc_pt < 0) { // Changed from baselineInc_pt <= 0 to baselineInc_pt < 0
alert("Please enter valid (non-negative) numbers. Baseline increment can be 0 to skip baseline grid.");
return;
}
function checkGridFit(abIdx, t_pt, b_pt, l_pt, r_pt, c, r, vg_pt, hg_pt) {
var rect = doc.artboards[abIdx].artboardRect;
var artW = rect[2] - rect[0] - l_pt - r_pt; var artH = rect[1] - rect[3] - t_pt - b_pt;
var minW = mmToPt(1), minH = mmToPt(1);
var failCol = false, failRow = false;
if (c > 1) {
var gutW = (c - 1) * vg_pt;
if (artW <= gutW || (artW - gutW)/c < minW) { failCol = true; }
}
if (r > 1) {
var gutH = (r - 1) * hg_pt;
if (artH <= gutH || (artH - gutH)/r < minH) { failRow = true; }
}
return {failCol: failCol, failRow: failRow};
}
var abIndices = [];
if (applyAllChk.value) { for (var i = 0; i < doc.artboards.length; i++) abIndices.push(i); } else { abIndices.push(abIdx); }
var vertGutterOverride = {}, horGutterOverride = {};
var warnedCol = false, warnedRow = false;
for (var i = 0; i < abIndices.length; i++) {
var check = checkGridFit(abIndices[i], top_pt, bottom_pt, left_pt, right_pt, cols, rows, vertGutter_pt, horGutter_pt);
if (check.failCol) {
if (!warnedCol) { alert("Column/gutter combination doesn't fit on at least one artboard. Vertical gutter is reset to default."); warnedCol = true; }
vertGutterOverride[abIndices[i]] = mmToPt(defaults.VertGutter);
}
if (check.failRow) {
if (!warnedRow) { alert("Row/gutter combination doesn't fit on at least one artboard. Horizontal gutter is reset to default."); warnedRow = true; }
horGutterOverride[abIndices[i]] = mmToPt(defaults.HorGutter);
}
}
// --- ENHANCED LAYER MANAGEMENT: Handle baseline layer conditionally ---
if (applyAllChk.value) {
deleteLayerByExactName(doc, "Margins and Columns");
// Only delete baseline layer if we're going to recreate it
if (baselineInc_pt > 0) {
deleteLayerByExactName(doc, "Baseline");
}
}
var marginsLayer = findLayer(doc, "Margins and Columns");
if (!marginsLayer) { marginsLayer = doc.layers.add(); marginsLayer.name = "Margins and Columns"; }
marginsLayer.locked = false; marginsLayer.visible = true;
// Only create baseline layer if we need it (baselineInc_pt > 0)
var baselineLayer = null;
if (baselineInc_pt > 0) {
baselineLayer = findLayer(doc, "Baseline");
if (!baselineLayer) { baselineLayer = doc.layers.add(); baselineLayer.name = "Baseline"; }
baselineLayer.locked = false; baselineLayer.visible = true;
}
for (var k = 0; k < abIndices.length; k++) {
var idx = abIndices[k];
var thisVertGutter_pt = vertGutterOverride[idx] !== undefined ? vertGutterOverride[idx] : vertGutter_pt;
var thisHorGutter_pt = horGutterOverride[idx] !== undefined ? horGutterOverride[idx] : horGutter_pt;
var ab = doc.artboards[idx];
if (!applyAllChk.value) {
removePathsForArtboard(marginsLayer, idx);
// Only clean baseline layer if it exists
if (baselineLayer) {
removePathsForArtboard(baselineLayer, idx);
}
}
// Always create margins and columns
addMarginsAndColumnsToLayer(marginsLayer, ab, idx, top_pt, bottom_pt, left_pt, right_pt, cols, thisVertGutter_pt, rows, thisHorGutter_pt);
// Only create baseline grid if increment > 0 and layer exists
if (baselineInc_pt > 0 && baselineLayer) {
addBaselineGridToLayer(baselineLayer, ab, idx, top_pt, bottom_pt, left_pt, right_pt, baselineStart_pt, baselineInc_pt);
}
// --- SAVE LOGIC REMAINS THE SAME ---
var valuesToSave = {
Top: addDefaultUnit(topInput.text, "margin"),
Bottom: addDefaultUnit(bottomInput.text, "margin"),
Left: addDefaultUnit(leftInput.text, "margin"),
Right: addDefaultUnit(rightInput.text, "margin"),
Columns: addDefaultUnit(colInput.text, "number"),
Rows: addDefaultUnit(rowInput.text, "number"),
VertGutter: addDefaultUnit(vertGutterInput.text, "gutter"),
HorGutter: addDefaultUnit(horGutterInput.text, "gutter"),
BaselineStart: addDefaultUnit(baselineStartInput.text, "margin"),
BaselineInc: addDefaultUnit(baselineIncInput.text, "baseline")
};
if (vertGutterOverride[idx] !== undefined) {
valuesToSave.VertGutter = defaults.VertGutter.toString() + "mm";
}
if (horGutterOverride[idx] !== undefined) {
valuesToSave.HorGutter = defaults.HorGutter.toString() + "mm";
}
saveSettingsToXML(settingsXMLPath, idx, valuesToSave);
}
// Lock layers that were created
marginsLayer.locked = true;
if (baselineLayer) {
baselineLayer.locked = true;
}
w.close();
};
w.center();
w.show();
}
showMarginsDialog();
Find more inspiration, events, and resources on the new Adobe Community
Explore Now