From 9c7b9b69a5d2d63126fb72ce24526f4d153e4ecc Mon Sep 17 00:00:00 2001 From: Ivica Ico Bukvic <ico@monsoon.(none)> Date: Thu, 8 Nov 2012 01:24:54 -0500 Subject: [PATCH] implemented new tidy option that offers intelligent alignment when pressed once, and then intelligent spacing if pressed the second time on the same selection --- src/g_editor.c | 430 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 429 insertions(+), 1 deletion(-) diff --git a/src/g_editor.c b/src/g_editor.c index 9b7b0334b..5d76acb26 100644 --- a/src/g_editor.c +++ b/src/g_editor.c @@ -12,6 +12,7 @@ #include "g_undo.h" #include "x_preset.h" #include <string.h> +#include "g_all_guis.h" void glist_readfrombinbuf(t_glist *x, t_binbuf *b, char *filename, int selectem); @@ -4765,12 +4766,439 @@ bad: (sink? class_getname(pd_class(&sink->g_pd)) : "???")); } +/* new implementation works in such a way that it first tries to line up all objects in the same line depending on the minimal distance between values (e.g. if objects' y values are closer than x values the alignment will happen vertically and vice-versa). If the objects already exhibit 0 difference across one axis, it will pick the top/left-most two objects and use them as a reference for spatialization between the remaining selected objects. any further tidy calls will be ignored */ + +// struct for storing spatially aware list of selected gobjects +typedef struct _sgobj +{ + t_gobj *s_g; + int s_x1; + int s_x2; + int s_y1; + int s_y2; + struct _sgobj *s_next; +} t_sgobj; + +static int sgobj_already_processed(t_gobj *y, t_sgobj *sg) { + while (sg) { + if (sg->s_g == y) + return(1); + sg = sg->s_next; + } + return(0); +} + +static int canvas_tidy_gobj_width(t_canvas *x, t_gobj *y) { + + int w = 0; + int x1, y1, x2, y2; + gobj_getrect(y, x, &x1, &y1, &x2, &y2); + w = x2 - x1; + //fprintf(stderr,"width = %d\n", w); + return(w); +} + +static int canvas_tidy_gobj_height(t_canvas *x, t_gobj *y) { + + int h = 0; + int x1, y1, x2, y2; + gobj_getrect(y, x, &x1, &y1, &x2, &y2); + h = y2 - y1; + //fprintf(stderr,"height = %d\n", h); + return(h); +} + +static void canvas_tidy(t_canvas *x) +{ + // if we have no editor, no selection, or only one object selected, return + if (!x->gl_editor || !x->gl_editor->e_selection || !x->gl_editor->e_selection->sel_next) return; + + //fprintf(stderr,"canvas_tidy\n"); + t_gobj *y; + t_text *yt, *rightmost_t = NULL, *topmost_t = NULL; + int h, v, hs, vs; // horizontal, vertical, horizontal respacing, vertical respacing + t_gobj *leftmost, *rightmost, *topmost, *bottommost; + int x1, x2, y1, y2; + int ox1, ox2, oy1, oy2; // object x and y dimensions + int cox1, cox2, coy1, coy2; // comparing object x and y dimensions + int dx, dy; // displacement variables + int i; // generic counter var + t_sgobj *sg, *tmpsg; // list of objects ordered spatially + int spacing = 0; // spacing between objects on respacing (this is adjustable) + int delta = 0; + + dx = dy = h = v = hs = vs = 0; + + t_selection *sel = x->gl_editor->e_selection; + y = sel->sel_what; + yt = (t_text *)y; + x1 = yt->te_xpix; + x2 = x1; + y1 = yt->te_ypix; + y2 = y1; + + leftmost = y; + topmost = y; + rightmost = y; + bottommost = y; + + sel = sel->sel_next; + + // first find out whether we are dealing with horizontal or vertical alignment or spatialization + while (sel) { + y = sel->sel_what; + yt = (t_text *)y; + + if (yt->te_xpix < x1) { + x1 = yt->te_xpix; + } + + if (yt->te_xpix > x2) { + x2 = yt->te_xpix; + } + + if (yt->te_ypix < y1) { + y1 = yt->te_ypix; + } + + if (yt->te_ypix > y2) { + y2 = yt->te_ypix; + } + + sel = sel->sel_next; + } + if (x2-x1 != 0 && x2-x1 < y2-y1) v = 1; //horizontal + else if (y2-y1 != 0 && y2-y1 <= x2-x1) h = 1; //vertical (takes precedence over vertical if two are equal) + else if (x2-x1 == 0) vs = 1; //vertically aligned respacing + else if (y2-y1 == 0) hs = 1; //horizontally aligned respacing + + //fprintf(stderr,"h=%d v=%d hs=%d vs=%d\n", h, v, hs, vs); + + // now find leftmost, topmost, rightmost, and bottommost object + sel = x->gl_editor->e_selection; + while (sel) { + y = sel->sel_what; + yt = (t_text *)y; + if(yt->te_xpix == x1) { + leftmost = y; + //fprintf(stderr,"leftmost %d\n", x1); + } + if(yt->te_xpix == x2) { + rightmost = y; + rightmost_t = (t_text *)y; + //fprintf(stderr,"rightmost %d\n", x2); + } + if(yt->te_ypix == y2) { + topmost = y; + topmost_t = (t_text *)y; + //fprintf(stderr,"topmost %d\n", y2); + } + if(yt->te_ypix == y1) { + bottommost = y; + //fprintf(stderr,"bottommost %d\n", y1); + } + sel = sel->sel_next; + } + + if (h == 1) { + // horizontal tidy (everyone lines up to the y of the leftmost object) + canvas_undo_add(x, 4, "motion", canvas_undo_set_move(x, 1)); + sel = x->gl_editor->e_selection; + yt = (t_text *)leftmost; + dy = yt->te_ypix; + + while (sel) { + y = sel->sel_what; + yt = (t_text *)y; + + //fprintf(stderr,"displace %d\n", dy - yt->te_ypix); + gobj_displace(y, x, 0, dy - yt->te_ypix); + + sel = sel->sel_next; + } + } + else if (v == 1) { + // vertical tidy (everyone lines up to the x of the bottommost object, since y axis is inverted) + canvas_undo_add(x, 4, "motion", canvas_undo_set_move(x, 1)); + sel = x->gl_editor->e_selection; + yt = (t_text *)bottommost; + dx = yt->te_xpix; + + while (sel) { + y = sel->sel_what; + yt = (t_text *)y; + + //fprintf(stderr,"displace %d\n", dx - yt->te_xpix); + gobj_displace(y, x, dx - yt->te_xpix, 0); + + sel = sel->sel_next; + } + } + else { + // first check if we have more than 2 objects selected (otherwise there is no point in doing this + sel = x->gl_editor->e_selection; + i = 1; + while (sel->sel_next) { + i++; + sel = sel->sel_next; + } + + // we now know we will do a respace which means we need to first order objects according to their physical location (horizontal or vertical) + if (hs == 1) { + + t_gobj *next_right = NULL; + t_text *next_right_t = NULL; + + yt = (t_text *)rightmost; + sg = (t_sgobj *)getbytes(sizeof(*sg)); + sg->s_g = rightmost; + sg->s_x1 = yt->te_xpix; + sg->s_x2 = yt->te_xpix + canvas_tidy_gobj_width(x, y); + sg->s_y1 = yt->te_ypix; + sg->s_y2 = yt->te_ypix + canvas_tidy_gobj_height(x, y); + sg->s_next = NULL; + + //fprintf(stderr,"%d: x=%d y=%d width=%d height=%d\n", i, yt->te_xpix, yt->te_ypix, canvas_tidy_gobj_width(x, y), canvas_tidy_gobj_height(x, y)); + + i--; + + while (i) { + //fprintf(stderr,"i=%d\n", i); + sel = x->gl_editor->e_selection; + while (sel) { + y = sel->sel_what; + yt = (t_text *)y; + + //fprintf(stderr, "already processed ? %d ... x=%d y=%d\n", sgobj_already_processed(y, sg), yt->te_xpix, yt->te_ypix); + + // we need to avoid duplicates + if (!sgobj_already_processed(y, sg)) { + if (!next_right && yt->te_xpix <= rightmost_t->te_xpix) { + next_right = y; + next_right_t = yt; + } + else if (next_right && yt->te_xpix >= next_right_t->te_xpix && yt->te_xpix <= rightmost_t->te_xpix) { + next_right = y; + next_right_t = yt; + } + } + + sel = sel->sel_next; + } + + tmpsg = (t_sgobj *)getbytes(sizeof(*sg)); + tmpsg->s_g = next_right; + tmpsg->s_x1 = next_right_t->te_xpix; + tmpsg->s_x2 = next_right_t->te_xpix + canvas_tidy_gobj_width(x, next_right); + tmpsg->s_y1 = next_right_t->te_ypix; + tmpsg->s_y2 = next_right_t->te_ypix + canvas_tidy_gobj_height(x, next_right); + tmpsg->s_next = sg; + sg = tmpsg; + + //fprintf(stderr,"%d: x=%d y=%d width=%d height=%d\n", i, next_right_t->te_xpix, next_right_t->te_ypix, canvas_tidy_gobj_width(x, next_right), canvas_tidy_gobj_height(x, next_right)); + + rightmost = next_right; + rightmost_t = next_right_t; + next_right = NULL; + + i--; + } + + //fprintf(stderr,"got this far\n"); + // now let's traverse the new list and find minimal spacing and use that as our reference + // if spacing is anywhere less than 0 (meaning objects overlap), use next legal value + // one that is greater than 0. If all values are < 0 then use default value (10). + tmpsg = sg; + while (tmpsg->s_next) { + //fprintf(stderr,"calculating spacing from: %d and %d\n", tmpsg->s_next->s_x1, tmpsg->s_x2); + if (tmpsg->s_next->s_x1 > tmpsg->s_x2 && (spacing <= 0 || (spacing > 0 && tmpsg->s_next->s_x1 - tmpsg->s_x2 < spacing))) + spacing = tmpsg->s_next->s_x1 - tmpsg->s_x2; + //fprintf(stderr,"spacing = %d\n", spacing); + tmpsg = tmpsg->s_next; + } + if (spacing <= 0) { +#ifdef PDL2ORK + if (sys_k12_mode) + spacing = 25; + else +#endif + spacing = 5; + } + + //fprintf(stderr,"final spacing = %d\n", spacing); + + //fprintf(stderr,"0...\n"); + + // now change all values in the list to their target values + tmpsg = sg; + while (tmpsg->s_next) { + //fprintf(stderr,"adjusting %d to %d + %d\n", tmpsg->s_next->s_x1, tmpsg->s_x2, spacing); + delta = tmpsg->s_next->s_x1 - (tmpsg->s_x2 + spacing); + tmpsg->s_next->s_x1 = tmpsg->s_next->s_x1 - delta; + tmpsg->s_next->s_x2 = tmpsg->s_next->s_x2 - delta; + tmpsg = tmpsg->s_next; + } + + //fprintf(stderr,"1...\n"); + + // create an undo checkpoint + canvas_undo_add(x, 4, "motion", canvas_undo_set_move(x, 1)); + + //fprintf(stderr,"2...\n"); + + // reposition all objects + tmpsg = sg; + while (tmpsg->s_next) { + yt = (t_text *)tmpsg->s_next->s_g; + //fprintf(stderr,"displace: %d %d\n", tmpsg->s_next->s_x1, yt->te_xpix); + gobj_displace(tmpsg->s_next->s_g, x, tmpsg->s_next->s_x1 - yt->te_xpix, 0); + tmpsg = tmpsg->s_next; + } + + //fprintf(stderr,"3...\n"); + + // free the temporary list of spatialized objects + while (sg) { + tmpsg = sg->s_next; + freebytes(sg, sizeof(*sg)); + sg = tmpsg; + } + } + else if (vs == 1) { + + t_gobj *next_top = NULL; + t_text *next_top_t = NULL; + + yt = (t_text *)topmost; + sg = (t_sgobj *)getbytes(sizeof(*sg)); + sg->s_g = topmost; + sg->s_x1 = yt->te_xpix; + sg->s_x2 = yt->te_xpix + canvas_tidy_gobj_width(x, y); + sg->s_y1 = yt->te_ypix; + sg->s_y2 = yt->te_ypix + canvas_tidy_gobj_height(x, y); + sg->s_next = NULL; + + //fprintf(stderr,"%d: x=%d y=%d width=%d height=%d\n", i, yt->te_xpix, yt->te_ypix, canvas_tidy_gobj_width(x, y), canvas_tidy_gobj_height(x, y)); + + i--; + + while (i) { + //fprintf(stderr,"i=%d\n", i); + sel = x->gl_editor->e_selection; + while (sel) { + y = sel->sel_what; + yt = (t_text *)y; + + //fprintf(stderr, "already processed ? %d ... x=%d y=%d\n", sgobj_already_processed(y, sg), yt->te_xpix, yt->te_ypix); + + // we need to avoid duplicates + if (!sgobj_already_processed(y, sg)) { + if (!next_top && yt->te_ypix <= topmost_t->te_ypix) { + next_top = y; + next_top_t = yt; + } + else if (next_top && yt->te_ypix >= next_top_t->te_ypix && yt->te_ypix <= topmost_t->te_ypix) { + next_top = y; + next_top_t = yt; + } + } + + sel = sel->sel_next; + } + + tmpsg = (t_sgobj *)getbytes(sizeof(*sg)); + tmpsg->s_g = next_top; + tmpsg->s_x1 = next_top_t->te_xpix; + tmpsg->s_x2 = next_top_t->te_xpix + canvas_tidy_gobj_width(x, next_top); + tmpsg->s_y1 = next_top_t->te_ypix; + tmpsg->s_y2 = next_top_t->te_ypix + canvas_tidy_gobj_height(x, next_top); + tmpsg->s_next = sg; + sg = tmpsg; + + //fprintf(stderr,"%d: x=%d y=%d width=%d height=%d\n", i, next_top_t->te_xpix, next_top_t->te_ypix, canvas_tidy_gobj_width(x, next_top), canvas_tidy_gobj_height(x, next_top)); + + topmost = next_top; + topmost_t = next_top_t; + next_top = NULL; + + i--; + } + + //fprintf(stderr,"got this far\n"); + // now let's traverse the new list and find minimal spacing and use that as our reference + // if spacing is anywhere less than 0 (meaning objects overlap), use next legal value + // one that is greater than 0. If all values are < 0 then use default value (10). + tmpsg = sg; + while (tmpsg->s_next) { + //fprintf(stderr,"calculating spacing from: %d and %d\n", tmpsg->s_next->s_y1, tmpsg->s_y2); + if (tmpsg->s_next->s_y1 > tmpsg->s_y2 && (spacing <= 0 || (spacing > 0 && tmpsg->s_next->s_y1 - tmpsg->s_y2 < spacing))) + spacing = tmpsg->s_next->s_y1 - tmpsg->s_y2; + //fprintf(stderr,"spacing = %d\n", spacing); + tmpsg = tmpsg->s_next; + } + if (spacing <= 0) { +#ifdef PDL2ORK + if (sys_k12_mode) + spacing = 25; + else +#endif + spacing = 5; + } + + //fprintf(stderr,"final spacing = %d\n", spacing); + + //fprintf(stderr,"0...\n"); + + // now change all values in the list to their target values + tmpsg = sg; + while (tmpsg->s_next) { + //fprintf(stderr,"adjusting %d to %d + %d\n", tmpsg->s_next->s_y1, tmpsg->s_y2, spacing); + delta = tmpsg->s_next->s_y1 - (tmpsg->s_y2 + spacing); + tmpsg->s_next->s_y1 = tmpsg->s_next->s_y1 - delta; + tmpsg->s_next->s_y2 = tmpsg->s_next->s_y2 - delta; + tmpsg = tmpsg->s_next; + } + + //fprintf(stderr,"1...\n"); + + // create an undo checkpoint + canvas_undo_add(x, 4, "motion", canvas_undo_set_move(x, 1)); + + //fprintf(stderr,"2...\n"); + + // reposition all objects + tmpsg = sg; + while (tmpsg->s_next) { + yt = (t_text *)tmpsg->s_next->s_g; + //fprintf(stderr,"displace: %d %d\n", tmpsg->s_next->s_y1, yt->te_ypix); + gobj_displace(tmpsg->s_next->s_g, x, 0, tmpsg->s_next->s_y1 - yt->te_ypix); + tmpsg = tmpsg->s_next; + } + + //fprintf(stderr,"3...\n"); + + // free the temporary list of spatialized objects + while (sg) { + tmpsg = sg->s_next; + freebytes(sg, sizeof(*sg)); + sg = tmpsg; + } + } + + } + canvas_dirty(x, 1); + sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x); +} + + +/* below is deprecated/old version of tidy left here for documentation/reuse purposes + currently it is inactive */ #define XTOLERANCE 20 #define YTOLERANCE 20 #define NHIST 15 /* LATER might have to speed this up */ -static void canvas_tidy(t_canvas *x) +static void canvas_tidyold(t_canvas *x) { t_gobj *y, *y2, *y3; int ax1, ay1, ax2, ay2, bx1, by1, bx2, by2; -- GitLab