Copy link to clipboard
Copied
I'd love to see an option in preferences under Units and Rulers to set the Ruler Origin (0,0) to be in a different location than the top left corner of the artboard, either on a document by document basis, or as a default - maybe with a toggle. A 3x3 grid of radio button selections such as top left, middle left, bottom left; top center, middle center, bottom center; top right, middle right, bottom right would be ideal, but a drop down list would work also. This would save having to zoom waaaaayyy in to the appropriate location and dragging the corner box of the ruler to (hopefully) line up with the exact pixel you're aiming for on each new artboard/file.
If there's already a simple way to do this that I'm unaware of, I'd love to know what it is!
Thanks!
mscureman
If you want to submit the radio button/dropdown idea (I'd +1) it you can submit it here:
Thanks for the feedback, kstohlmeyer! I knew about dragging the upper left corner, but didn't know about the Shift key modifier. Helpful!
Also, I submitted this as an "Idea" on the feedback forum here:
Set Ruler Origin Location in Preferences, New Document Dialog or Menu
Copy link to clipboard
Copied
"but the Action did not record my dragging the origin to the lower left corner." The drag or using the arrow keys when the move tool is selected puts Photoshop into a "follow on" or "reusable" action. Instead of recording "move one pixel down" over and over and over again Photoshop keeps track and just ends up with "move 4 pixels down." If you have actions panel recording you can see this, select move tool, move with arrow or mouse, then do something else, like select another layer, and you get two entries in actions panel, the final resting spot of the move and the layer select. If you can get the dimensions and location of the thing you are moving then just move it to "0, x" for left, "x, 0" for top. Does that work?
But I DO like the idea of a command that says, "move to the top" have you played with the alignment options in the move tool bar. Select two layers and pick: "Align vertical centers" that records in the actions panel.
Copy link to clipboard
Copied
Here is an updated 1.4 version that includes functionality to disable the radio buttons when values are entered into the X & Y coordinate fields.
/*
Set Ruler Origin to User Input v1-4.jsx
Version 1.4, 12th October 2024 - Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-discussions/feature-request-set-ruler-origin-location-in-photoshop/td-p/10844115/page/2#U14912183
*/
#target photoshop
if (app.documents.length > 0) {
// Save the current ruler units and set to pixels
var savedRuler = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
// Main window
var dialogWindow = new Window("dialog", undefined, undefined, {
closeButton: false
});
dialogWindow.text = "Set Ruler Origin - v1.4"; // Remember to update this to match the header!
dialogWindow.preferredSize.width = 410;
dialogWindow.preferredSize.height = 100;
dialogWindow.orientation = "row";
dialogWindow.alignChildren = ["left", "center"];
dialogWindow.spacing = 10;
dialogWindow.margins = 15;
// Main panel
var mainPanel = dialogWindow.add("panel", undefined, "Ruler Origin Point Location");
mainPanel.orientation = "column";
mainPanel.alignChildren = ["left", "top"]; // Align to top
mainPanel.spacing = 10;
mainPanel.margins = 10;
// Group 1
var group1 = mainPanel.add("group", undefined, {
name: "group1"
});
group1.orientation = "row";
group1.alignChildren = ["left", "center"];
group1.spacing = 10;
group1.margins = 0;
// Upper group
var upperGroup = group1.add("group", undefined, {
name: "upperGroup"
});
upperGroup.orientation = "column";
upperGroup.alignChildren = ["left", "center"];
upperGroup.spacing = 10;
upperGroup.margins = 0;
var upperLeft = upperGroup.add("radiobutton", undefined, undefined, {
name: "upperLeft"
});
upperLeft.text = "Upper Left";
var middleLeft = upperGroup.add("radiobutton", undefined, undefined, {
name: "middleLeft"
});
middleLeft.text = "Middle Left";
var lowerLeft = upperGroup.add("radiobutton", undefined, undefined, {
name: "lowerLeft"
});
lowerLeft.text = "Lower Left";
// Middle group
var middleGroup = group1.add("group", undefined, {
name: "middleGroup"
});
middleGroup.orientation = "column";
middleGroup.alignChildren = ["left", "center"];
middleGroup.spacing = 10;
middleGroup.margins = 0;
var upperCenter = middleGroup.add("radiobutton", undefined, undefined, {
name: "upperCenter"
});
upperCenter.text = "Upper Center";
var middleCenter = middleGroup.add("radiobutton", undefined, undefined, {
name: "middleCenter"
});
middleCenter.text = "Middle Center";
var lowerCenter = middleGroup.add("radiobutton", undefined, undefined, {
name: "lowerCenter"
});
lowerCenter.text = "Lower Center";
// Lower group
var lowerGroup = group1.add("group", undefined, {
name: "lowerGroup"
});
lowerGroup.orientation = "column";
lowerGroup.alignChildren = ["left", "center"];
lowerGroup.spacing = 10;
lowerGroup.margins = 0;
var upperRight = lowerGroup.add("radiobutton", undefined, undefined, {
name: "upperRight"
});
upperRight.text = "Upper Right";
var middleRight = lowerGroup.add("radiobutton", undefined, undefined, {
name: "middleRight"
});
middleRight.text = "Middle Right";
var lowerRight = lowerGroup.add("radiobutton", undefined, undefined, {
name: "lowerRight"
});
lowerRight.text = "Lower Right";
// X & Y group
var xyGroup = dialogWindow.add("group", undefined, { name: "xyGroup" });
xyGroup.orientation = "row";
xyGroup.alignChildren = ["left", "top"]; // Align to top
xyGroup.spacing = 0;
xyGroup.margins = [0, 0, 0, 0];
xyGroup.alignment = ["left", "top"]; // Align group to the top
// X & Y panel
var xyPanel = xyGroup.add("panel", undefined, undefined, { name: "xyPanel" });
xyPanel.text = "Coordinates";
xyPanel.orientation = "column";
xyPanel.alignChildren = ["left", "center"];
xyPanel.spacing = 5;
xyPanel.margins = [10, 10, 10, 10];
xyPanel.alignment = ["left", "center"];
// Create a group for X input and label
var xGroup = xyPanel.add("group");
xGroup.orientation = "row";
xGroup.alignChildren = ["left", "center"];
// Add X input field
var xValue = xGroup.add('edittext {properties: {name: "xValue"}}');
xValue.helpTip = "Enter the X value";
xValue.preferredSize.width = 80;
xValue.text = "";
xValue.addEventListener('keydown', NumericEditKeyboardHandler);
xValue.addEventListener('changing', updateRadioButtons);
// Add X label
var xLabel = xGroup.add("statictext", undefined, "X");
xLabel.preferredSize.width = 20; // Set preferred width for label alignment
// Create a group for Y input and label
var yGroup = xyPanel.add("group");
yGroup.orientation = "row";
yGroup.alignChildren = ["left", "center"];
// Add Y input field
var yValue = yGroup.add('edittext {properties: {name: "yValue"}}');
yValue.helpTip = "Enter the Y value";
yValue.preferredSize.width = 80;
yValue.text = "";
yValue.addEventListener('keydown', NumericEditKeyboardHandler);
yValue.addEventListener('changing', updateRadioButtons);
// Add Y label
var yLabel = yGroup.add("statictext", undefined, "Y");
yLabel.preferredSize.width = 20; // Set preferred width for label alignment
var radioButtons = [upperLeft, middleLeft, lowerLeft, upperCenter, middleCenter, lowerCenter, upperRight, middleRight, lowerRight];
for (var i = 0; i < radioButtons.length; i++) {
radioButtons[i].addEventListener('click', function () {
xValue.text = "";
yValue.text = "";
updateRadioButtons();
});
}
////////////////////// peter kahrel scriptUI for dummies - make multiple groups act as one group //////////////////////
upperGroup.addEventListener("click", function () {
for (var i = 0; i < middleGroup.children.length; i++)
middleGroup.children[i].value = false;
});
upperGroup.addEventListener("click", function () {
for (var i = 0; i < lowerGroup.children.length; i++)
lowerGroup.children[i].value = false;
});
middleGroup.addEventListener("click", function () {
for (var i = 0; i < upperGroup.children.length; i++)
upperGroup.children[i].value = false;
});
middleGroup.addEventListener("click", function () {
for (var i = 0; i < lowerGroup.children.length; i++)
lowerGroup.children[i].value = false;
});
lowerGroup.addEventListener("click", function () {
for (var i = 0; i < middleGroup.children.length; i++)
middleGroup.children[i].value = false;
});
lowerGroup.addEventListener("click", function () {
for (var i = 0; i < upperGroup.children.length; i++)
upperGroup.children[i].value = false;
});
// OK & Cancel button group
var okGroup = dialogWindow.add("group", undefined, {
name: "okGroup"
});
okGroup.orientation = "column"; // Set to column for vertical layout
okGroup.alignChildren = ["fill", "top"]; // Fill width, align to top
okGroup.spacing = 12; // Space between buttons
okGroup.margins = [1, 1, 1, 1]; // Margins around the group
var okButton = okGroup.add("button", undefined, undefined, {
name: "okButton"
});
okButton.text = "OK";
// Set the button to fill the width of the column
okButton.preferredSize.width = 100; // Set preferred width (adjust as needed)
var cancelButton = okGroup.add("button", undefined, undefined, {
name: "cancelButton"
});
cancelButton.text = "Cancel";
// Set the button to fill the width of the column
cancelButton.preferredSize.width = 100; // Set preferred width (adjust as needed)
////////////////////////////// tom_ruark @ adobe //////////////////////////////
/* https://feedback.photoshop.com/conversations/photoshop/photoshop-ability-to-ruler-origin-by-script/5f5f45bb4b561a3d425c7b32 */
// Version 2016.11.18
// Show how to get and set the ruler origin point for the current document
// Values are in pixels shifted 16 bits
// some constants to make it more readable
const classProperty = app.stringIDToTypeID("property");
const krulerOriginHStr = app.stringIDToTypeID("rulerOriginH");
const krulerOriginVStr = app.stringIDToTypeID("rulerOriginV");
const classDocument = app.stringIDToTypeID("document");
const typeOrdinal = app.stringIDToTypeID("ordinal");
const enumTarget = app.stringIDToTypeID("targetEnum");
const typeNULL = app.stringIDToTypeID("null");
const keyTo = app.stringIDToTypeID("to");
const eventSet = app.stringIDToTypeID("set");
// Get the current values
GetRulerOrigin().toSource();
function GetRulerOrigin() {
var ro = {};
ro.horizontal = GetInfo(classDocument, krulerOriginHStr) >> 16;
ro.vertical = GetInfo(classDocument, krulerOriginVStr) >> 16;
return ro;
}
function SetRulerOrigin_Horiz(horiz) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putProperty(classProperty, krulerOriginHStr);
ref.putEnumerated(classDocument, typeOrdinal, enumTarget);
desc.putReference(typeNULL, ref);
desc.putInteger(keyTo, horiz << 16);
executeAction(eventSet, desc, DialogModes.NO);
}
function SetRulerOrigin_Vert(vert) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putProperty(classProperty, krulerOriginVStr);
ref.putEnumerated(classDocument, typeOrdinal, enumTarget);
desc.putReference(typeNULL, ref);
desc.putInteger(keyTo, vert << 16);
executeAction(eventSet, desc, DialogModes.NO);
}
///////////////////////////////////////////////////////////////////////////////
// Function: GetInfo
// Usage: Get information from Photoshop
// Input: desiredClass, classApplication, classLayer, etc.
// desiredKey, optional specific key to get instead of everything
// this is recommended as all keys is an expensive call
// Return: ActionDescriptor or single value depending on what is asked for
///////////////////////////////////////////////////////////////////////////////
function GetInfo(desiredClass, desiredKey) {
var reference = new ActionReference();
if (typeof desiredKey != "undefined") {
reference.putProperty(stringIDToTypeID("property"), desiredKey);
}
reference.putEnumerated(desiredClass, stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
var desc = executeActionGet(reference);
if (typeof desiredKey != "undefined") {
return GetItemFromDescriptor(desc, desiredKey);
}
return desc;
}
///////////////////////////////////////////////////////////////////////////////
// Function: GetItemFromDescriptor
// Usage: Get a specific key from an ActionDescriptor
// Input: desc (ActionDescriptor), valid ActionDescriptor to pull info from
// desiredKey (Number), key in question, use charIDToTypeID() or
// stringIDToTypeID()
// Return: ActionDescriptor or single value depending on what is asked for
///////////////////////////////////////////////////////////////////////////////
function GetItemFromDescriptor(desc, desiredKey) {
if (desc.hasKey(desiredKey)) {
var typeID = desc.getType(desiredKey);
switch (typeID) {
case DescValueType.BOOLEANTYPE:
return desc.getBoolean(desiredKey);
break;
case DescValueType.STRINGTYPE:
return desc.getString(desiredKey);
break;
case DescValueType.DOUBLETYPE:
return desc.getDouble(desiredKey);
break;
case DescValueType.INTEGERTYPE:
return desc.getInteger(desiredKey);
break;
case DescValueType.LARGEINTEGERTYPE:
return desc.getLargeInteger(desiredKey);
break;
case DescValueType.OBJECTTYPE:
return desc.getObjectValue(desiredKey);
break;
case DescValueType.UNITDOUBLE:
var newT = desc.getUnitDoubleType(desiredKey);
var newV = desc.getUnitDoubleValue(desiredKey);
return new UnitValue(newV, newT);
break;
case DescValueType.ENUMERATEDTYPE:
return desc.getEnumerationValue(desiredKey);
break;
case DescValueType.CLASSTYPE:
return desc.getClass(desiredKey);
break;
case DescValueType.ALIASTYPE:
return desc.getPath(desiredKey);
break;
case DescValueType.RAWTYPE:
var tempStr = desc.getData(desiredKey);
var rawData = new Array();
for (var tempi = 0; tempi < tempStr.length; tempi++) {
rawData[tempi] = tempStr.charCodeAt(tempi);
}
return rawData;
break;
case DescValueType.REFERENCETYPE:
return desc.getReference(desiredKey);
break;
case DescValueType.LISTTYPE:
return desc.getList(desiredKey);
break;
default:
return;
}
}
return;
}
////////////////////////////// tom_ruark @ adobe //////////////////////////////
okButton.onClick = function () {
dialogWindow.close();
// Link function parameters to X & Y field values
if (xValue.text.length > 0) {
// Reset ruler origin to zero for a known start point
SetRulerOrigin_Horiz(0);
// Set ruler origin to variables
SetRulerOrigin_Horiz(xValue.text);
}
if (yValue.text.length > 0) {
// Reset ruler origin to zero for a known start point
SetRulerOrigin_Vert(0);
// Set ruler origin to variables
SetRulerOrigin_Vert(yValue.text);
}
// Canvas variables
var rE = app.activeDocument.width; // rightEdge
var hC = app.activeDocument.width / 2; // horizontalCenter
var vC = app.activeDocument.height / 2; // verticalCenter
var bE = app.activeDocument.height; // bottomEdge
// Link function parameters to radio buttons
if (upperLeft.value === true) {
// Reset ruler origin to zero for a known start point
SetRulerOrigin_Horiz(0);
SetRulerOrigin_Vert(0);
}
if (upperCenter.value === true) {
// Reset ruler origin to zero for a known start point
SetRulerOrigin_Horiz(0);
SetRulerOrigin_Vert(0);
// Set ruler origin to variables
SetRulerOrigin_Horiz(hC);
SetRulerOrigin_Vert(0);
}
if (upperRight.value === true) {
// Reset ruler origin to zero for a known start point
SetRulerOrigin_Horiz(0);
SetRulerOrigin_Vert(0);
// Set ruler origin to variables
SetRulerOrigin_Horiz(rE);
SetRulerOrigin_Vert(0);
}
if (middleLeft.value === true) {
// Reset ruler origin to zero for a known start point
SetRulerOrigin_Horiz(0);
SetRulerOrigin_Vert(0);
// Set ruler origin to variables
SetRulerOrigin_Horiz(0);
SetRulerOrigin_Vert(vC);
}
if (middleCenter.value === true) {
// Reset ruler origin to zero for a known start point
SetRulerOrigin_Horiz(0);
SetRulerOrigin_Vert(0);
// Set ruler origin to variables
SetRulerOrigin_Horiz(hC);
SetRulerOrigin_Vert(vC);
}
if (middleRight.value === true) {
// Reset ruler origin to zero for a known start point
SetRulerOrigin_Horiz(0);
SetRulerOrigin_Vert(0);
// Set ruler origin to variables
SetRulerOrigin_Horiz(rE);
SetRulerOrigin_Vert(vC);
}
if (lowerLeft.value === true) {
// Reset ruler origin to zero for a known start point
SetRulerOrigin_Horiz(0);
SetRulerOrigin_Vert(0);
// Set ruler origin to variables
SetRulerOrigin_Horiz(0);
SetRulerOrigin_Vert(bE);
}
if (lowerCenter.value === true) {
// Reset ruler origin to zero for a known start point
SetRulerOrigin_Horiz(0);
SetRulerOrigin_Vert(0);
// Set ruler origin to variables
SetRulerOrigin_Horiz(hC);
SetRulerOrigin_Vert(bE);
}
if (lowerRight.value === true) {
// Reset ruler origin to zero for a known start point
SetRulerOrigin_Horiz(0);
SetRulerOrigin_Vert(0);
// Set ruler origin to variables
SetRulerOrigin_Horiz(rE);
SetRulerOrigin_Vert(bE);
}
}
// Execute window;
if (dialogWindow.show() == 1) {
// OK pressed
} else {
// Cancel pressed
}
////////////////////////////////// mike hale //////////////////////////////////
// Function to limit keyboard entry to digits
function NumericEditKeyboardHandler(event) {
try {
var keyIsOK = KeyIsNumeric(event) ||
KeyIsDelete(event) ||
KeyIsLRArrow(event) ||
KeyIsTabEnterEscape(event);
if (!keyIsOK) {
// Bad input: tell ScriptUI not to accept the keydown event
event.preventDefault();
/*
Notify user of invalid input: make sure NOT
to put up an alert dialog or do anything which
requires user interaction, because that
interferes with preventing the 'default'
action for the keydown event */
app.beep();
}
} catch (e) {
// alert ("Ack! bug in NumericEditKeyboardHandler: " + e);
}
}
function updateRadioButtons() {
var disableRadios = xValue.text.length > 0 || yValue.text.length > 0;
var radioButtons = [upperLeft, middleLeft, lowerLeft, upperCenter, middleCenter, lowerCenter, upperRight, middleRight, lowerRight];
for (var i = 0; i < radioButtons.length; i++) {
radioButtons[i].enabled = !disableRadios;
if (disableRadios) {
radioButtons[i].value = false;
}
}
}
xValue.addEventListener('changing', updateRadioButtons);
yValue.addEventListener('changing', updateRadioButtons);
function updateRadioButtons() {
var disableRadios = xValue.text.length > 0 || yValue.text.length > 0;
// Disable or enable all radio buttons
upperLeft.enabled = !disableRadios;
middleLeft.enabled = !disableRadios;
lowerLeft.enabled = !disableRadios;
upperCenter.enabled = !disableRadios;
middleCenter.enabled = !disableRadios;
lowerCenter.enabled = !disableRadios;
upperRight.enabled = !disableRadios;
middleRight.enabled = !disableRadios;
lowerRight.enabled = !disableRadios;
// Uncheck all radio buttons if disabled
if (disableRadios) {
upperLeft.value = false;
middleLeft.value = false;
lowerLeft.value = false;
upperCenter.value = false;
middleCenter.value = false;
lowerCenter.value = false;
upperRight.value = false;
middleRight.value = false;
lowerRight.value = false;
}
}
function KeyHasModifier(event) {
return event.shiftKey || event.ctrlKey || event.altKey || event.metaKey;
}
function KeyIsNumeric(event) {
return (event.keyName >= '0') && (event.keyName <= '9') && !KeyHasModifier(event);
}
function KeyIsDelete(event) {
return (event.keyName == 'Backspace') && !(event.ctrlKey);
}
function KeyIsLRArrow(event) {
return ((event.keyName == 'Left') || (event.keyName == 'Right')) && !(event.altKey || event.metaKey);
}
function KeyIsTabEnterEscape(event) {
return event.keyName == 'Tab' || event.keyName == 'Enter' || event.keyName == 'Escape';
}
////////////////////////////////// mike hale //////////////////////////////////
// Restore the ruler units
app.preferences.rulerUnits = savedRuler;
}
else {
alert('A document must be open to use this script!');
}
https://prepression.blogspot.com/2017/11/downloading-and-installing-adobe-scripts.html