Changed the positioning of the Margin property to be single-column.
This avoids concern with certain labels being obscure when the
preference window is not fullscreen or is rather small.
Forgot to add this one in the cleanup commit, but this refactors
the poll function to use a generator expression instead of a list.
This avoids having to make an entire list of selected nodes just to
find out whether at least two nodes are selected.
Final cleanup of the operator before opening it as a pull request.
Moved the midpoint calculation to its own staticmethod since it
is called multiple times, and being named "get_midpoint" should
make it what it is doing clear for anybody reading the code.
Additionally, trailing whitespace has been cleaned out, and some
parentheses are added to make certain expressions clearer.
Node dimensions are taken into account in order to properly align nodes, but the dimensions of reroutes lead to them getting placed off-center during alignment. According to the API, reroutes have a dimension of (16, 16) units, but visually, dimensions of 10 units instead of 16 seem to be closer to what the user sees. The changes in this commit make it so that the calculations use those dimensions instead, which results in visually more even spacing between nodes and reroutes.
Additionally, the fact that a hidden state (where node.hide == True)
would not affect placement calculation for reroutes, as opposed to
hidden nodes where it does, having separated placement logic for
reroutes and nodes seems justified enough to implement.
Correcting for the position of reroutes however, does seem to introduce
drift perpendicular to whatever axis the alignment takes place in. At the
cost of doing more calculations, addressing this actually compresses the
code as the nodes now always have to be repositioned in both axes to
avoid drift.
The Align Nodes operator has functionality for both horizontal and
vertical alignment, but which axis was used is something that was
automatically decided by the operator. While this is sufficient in most
of cases, there is a good number of instances in which the automatic
alignment is not ideal. Such as when a user may want to turn a row of
nodes into a column, and vice versa, for example.
This commit aims to make the operator more flexible by giving the user
the option to explicitly choose which axis they would want the alignment
to occur in. Additional buttons in the UI panel and context menu were
added for these modes, currently named "Align X" and "Align Y". The
"Align Nodes" button has been also renamed to "Auto-Align Nodes" for
better clarity.
In conjunction to that, a property is added in the addon's preferences
menu that allows the user to specify different spacings for X and Y
alignment. This gets rid of the hard coded (0.3 * margin) expression for
vertical alignment, and allows the user to customize the operator
whatever margins they find ideal. Layout changes in the user preferences
UI have been made to accomodate this property, how this was
approached is tentative and could be change given
subsequent review/feedback.
The commit preceding this one introduced code that applied corrective
offsets to hidden nodes so that they would be visually aligned with non-
hidden nodes. A separate calculation for calculating midpoints did not
factor in those offsets, leading to a bug wherein nodes slowly inch
downward when a horizontal align was applied repeatedly.
This behavior occurs specifically during horizontal alignment where the
active node is not selected. The changes in this commit aim to fix that
behavior by accounting for said corrective offsets during midpoint
calculation. Some stylistic code changes are also applied to
relevant code for better readability.
For collapsed/hidden nodes, their origin is located on their middle-left point,
instead of the top-left corner like in uncollapsed nodes. This wasn't
fully taken into consideration by the original code, leading to inaccuracies
when aligning hidden nodes, which this commit aims to address.
The changes implemented by this commit are as follows:
1.) Whether a node is hidden or not is no longer considered during
horizontal alignment, which avoids uneven spacing. As hiding a node
only affects its vertical dimensions, not its horizontal one.
2.) Added corrective offsets for when vertically aligning hidden nodes.
Due to how their origins are positioned, the original code would align
hidden nodes by their bottoms, instead of their middle like in
non-hidden nodes. So an extra offset was needed to align hidden nodes
by their center.
3.) Improved consistency when aligning non-hidden and hidden nodes
together. The original code's inaccuracies become most apparent when
mixing both types of nodes together, where uneven margins and
overlapping frequently occurs.
Refactored NWAlignNodes to make it easier to implement future changes.
This is done as a cleanup and precursor to later commits
planned on this branch.
Notable changes in this commit are as follows:
1.) Used .sort() instead of sorted().
This avoids making an extra copy of the list, and is more succinct and
reflective on the original code's intention of an in-place sort.
2.) Moved is_horizontal checks to occur out of loops.
The variable doesn't change per node, so it makes more sense to
not repeatedly check it while iterating nodes. Putting it outside
of loops also separates horizontal and vertical alignment behavior,
which would be needed for later bug fixes down the line.
3.) Changed all instances of "x / 2" to "0.5 * x".
Both cases of dividing by 2 and multiplying by 0.5 occur in the code,
this commit changed all of them to be consistent. It could be debated
which one is more readable, but multiplying by a factor would probably
be more workable if ever options for left or right-aligning and
top or bottom-aligning would be implemented in the future.
The calculations for the Align Nodes operator currently uses
node.location, which is relative to the frame a node is parented to.
This works fine when the selected nodes are not in a frame, or when
they're all parented under the same frame, but breaks in cases where
the nodes are inside separate frames.
The commit fixes this by implementing a context manager that
temporarily unframes the selected nodes, allowing the operator to
do its calculations using the nodes' absolute locations, before
returning the nodes to their parent frames after execution. This
allows the operator to work in whatever configuration the selected
nodes are framed in.
This commit adds a poll check for the Align Nodes
operator that only allows execution if at least two non-
frame nodes are selected. This is intended to address
two behaviors in the operator that work exactly as
intended but are neither intuitive for the end user.
First, frames are ignored by this operator, as they're not
relevant to the calculations being done. However, this is
not made apparent to the user in any way. The poll
function check hopes to address this by not allowing the user
to call the operator in cases where only frames are selected.
Second, is that when the operator is given an empty selection,
it is coded to act as if all nodes were selected. This doesn't
seem to offer much in the way of practical utility, since a user
can easily just call Select All before calling the operator. If
anything, it seems to be more a cause for confusion,
as can be seen in the relevant issue.
Since the poll function does not allow execution for empty
selections, the aforementioned behavior has been rendered
obsolete and was removed. Overall, the new behavior of being
unable to call Align Nodes when no nodes are selected
would seem to be more in line with how a user might
reasonably expect the operator to behave.