/* ---------------------------------------------------------------------- * moves all names of an element to a new position */ static void * MoveElementName (ElementTypePtr Element) { if (PCB->ElementOn && (FRONT (Element) || PCB->InvisibleObjectsOn)) { EraseElementName (Element); ELEMENTTEXT_LOOP (Element); { if (PCB->Data->name_tree[n]) r_delete_entry (PCB->Data->name_tree[n], (BoxType *)text); MOVE_TEXT_LOWLEVEL (text, DeltaX, DeltaY); if (PCB->Data->name_tree[n]) r_insert_entry (PCB->Data->name_tree[n], (BoxType *)text, 0); } END_LOOP; DrawElementName (Element); Draw (); } else { ELEMENTTEXT_LOOP (Element); { if (PCB->Data->name_tree[n]) r_delete_entry (PCB->Data->name_tree[n], (BoxType *)text); MOVE_TEXT_LOWLEVEL (text, DeltaX, DeltaY); if (PCB->Data->name_tree[n]) r_insert_entry (PCB->Data->name_tree[n], (BoxType *)text, 0); } END_LOOP; } return (Element); }
/* --------------------------------------------------------------------------- * moves a text object */ static void * MoveText (LayerTypePtr Layer, TextTypePtr Text) { RestoreToPolygon (PCB->Data, TEXT_TYPE, Layer, Text); r_delete_entry (Layer->text_tree, (BoxType *)Text); if (Layer->On) { EraseText (Layer, Text); MOVE_TEXT_LOWLEVEL (Text, DeltaX, DeltaY); DrawText (Layer, Text); Draw (); } else MOVE_TEXT_LOWLEVEL (Text, DeltaX, DeltaY); r_insert_entry (Layer->text_tree, (BoxType *)Text, 0); ClearFromPolygon (PCB->Data, TEXT_TYPE, Layer, Text); return (Text); }
static void * MyMoveTextLowLevel (LayerType *Layer, TextType *Text, Coord dx, Coord dy) { if (Layer) r_delete_entry (Layer->text_tree, (BoxType *) Text); MOVE_TEXT_LOWLEVEL (Text, dx, dy); if (Layer) r_insert_entry (Layer->text_tree, (BoxType *) Text, 0); return Text; }
/* --------------------------------------------------------------------------- * moves a element by +-X and +-Y */ void MoveElementLowLevel (DataTypePtr Data, ElementTypePtr Element, Coord DX, Coord DY) { if (Data) r_delete_entry (Data->element_tree, (BoxType *)Element); ELEMENTLINE_LOOP (Element); { MOVE_LINE_LOWLEVEL (line, DX, DY); } END_LOOP; PIN_LOOP (Element); { if (Data) { r_delete_entry (Data->pin_tree, (BoxType *)pin); RestoreToPolygon (Data, PIN_TYPE, Element, pin); } MOVE_PIN_LOWLEVEL (pin, DX, DY); if (Data) { r_insert_entry (Data->pin_tree, (BoxType *)pin, 0); ClearFromPolygon (Data, PIN_TYPE, Element, pin); } } END_LOOP; PAD_LOOP (Element); { if (Data) { r_delete_entry (Data->pad_tree, (BoxType *)pad); RestoreToPolygon (Data, PAD_TYPE, Element, pad); } MOVE_PAD_LOWLEVEL (pad, DX, DY); if (Data) { r_insert_entry (Data->pad_tree, (BoxType *)pad, 0); ClearFromPolygon (Data, PAD_TYPE, Element, pad); } } END_LOOP; ARC_LOOP (Element); { MOVE_ARC_LOWLEVEL (arc, DX, DY); } END_LOOP; ELEMENTTEXT_LOOP (Element); { if (Data && Data->name_tree[n]) r_delete_entry (PCB->Data->name_tree[n], (BoxType *)text); MOVE_TEXT_LOWLEVEL (text, DX, DY); if (Data && Data->name_tree[n]) r_insert_entry (PCB->Data->name_tree[n], (BoxType *)text, 0); } END_LOOP; MOVE_BOX_LOWLEVEL (&Element->BoundingBox, DX, DY); MOVE_BOX_LOWLEVEL (&Element->VBox, DX, DY); MOVE (Element->MarkX, Element->MarkY, DX, DY); if (Data) r_insert_entry (Data->element_tree, (BoxType *)Element, 0); }
/* * DistributeText(X, [Lefts/Rights/Centers/Gaps, [First/Last/Crosshair, First/Last/Crosshair[, Gridless]]]) * DistributeText(Y, [Tops/Bottoms/Centers/Gaps, [First/Last/Crosshair, First/Last/Crosshair[, Gridless]]]) * * As with align, plus: * * Gaps - Make gaps even rather than spreading points evenly * First, Last, * Crosshair - Two arguments specifying both ends of the * distribution, they can't both be the same. * * Defaults are Lefts/Tops, First, Last * * Distributed texts always retain the same relative order they had * before they were distributed. */ static int distributetext(int argc, char **argv, Coord x, Coord y) { int dir; int point; int refa, refb; int gridless; Coord s, e, slack; int divisor; int changed = 0; int i; if (argc < 1 || argc == 3 || argc > 4) { AFAIL(distributetext); } /* parse direction arg */ switch ((dir = keyword(ARG(0)))) { case K_X: case K_Y: break; default: AFAIL(distributetext); } /* parse point (within each element) which will be distributed */ switch ((point = keyword(ARG(1)))) { case K_Centers: case K_Gaps: break; case K_Lefts: case K_Rights: if (dir == K_Y) { AFAIL(distributetext); } break; case K_Tops: case K_Bottoms: if (dir == K_X) { AFAIL(distributetext); } break; case K_none: /* default value */ if (dir == K_X) { point = K_Lefts; } else { point = K_Tops; } break; default: AFAIL(distributetext); } /* parse reference which will determine first distribution coordinate */ switch ((refa = keyword(ARG(2)))) { case K_First: case K_Last: case K_Average: case K_Crosshair: break; case K_none: refa = K_First; /* default value */ break; default: AFAIL(distributetext); } /* parse reference which will determine final distribution coordinate */ switch ((refb = keyword(ARG(3)))) { case K_First: case K_Last: case K_Average: case K_Crosshair: break; case K_none: refb = K_Last; /* default value */ break; default: AFAIL(distributetext); } if (refa == refb) { AFAIL(distributetext); } /* optionally work off the grid (solar cells!) */ switch (keyword(ARG(4))) { case K_Gridless: gridless = 1; break; case K_none: gridless = 0; break; default: AFAIL(distributetext); } SaveUndoSerialNumber(); /* build list of texts in orthogonal axis order */ sort_texts_by_pos(K_distributetext, dir, point); /* find the endpoints given the above options */ s = reference_coord(K_distributetext, x, y, dir, point, refa); e = reference_coord(K_distributetext, x, y, dir, point, refb); slack = e - s; /* use this divisor to calculate spacing (for 1 elt, avoid 1/0) */ divisor = (ntexts_by_pos > 1) ? (ntexts_by_pos - 1) : 1; /* even the gaps instead of the edges or whatnot */ /* find the "slack" in the row */ if (point == K_Gaps) { Coord w; /* subtract all the "widths" from the slack */ for (i = 0; i < ntexts_by_pos; ++i) { TextType *text = texts_by_pos[i].text; /* coord doesn't care if I mix Lefts/Tops */ w = texts_by_pos[i].width = coord(text, dir, K_Rights) - coord(text, dir, K_Lefts); /* Gaps distribution is on centers, so half of * first and last text don't count */ if (i == 0 || i == ntexts_by_pos - 1) { w /= 2; } slack -= w; } /* slack could be negative */ } /* move all selected texts to the new coordinate */ for (i = 0; i < ntexts_by_pos; ++i) { TextType *text = texts_by_pos[i].text; int type = texts_by_pos[i].type; Coord p, q, dp, dx, dy; /* find reference point for this text */ q = s + slack * i / divisor; /* find delta from reference point to reference point */ p = coord(text, dir, point); dp = q - p; /* ...but if we're gridful, keep the mark on the grid */ /* TODO re-enable grid if (! gridless) { dp -= (coord(text, dir, K_Marks) + dp) % (long) (PCB->Grid); } */ if (dp) { /* move from generic to X or Y */ dx = dy = dp; if (dir == K_X) dy = 0; else dx = 0; /* need to know if the text is part of an element, * all are TEXT_TYPE, but text associated with an * element is also ELEMENTNAME_TYPE. For undo, this is * significant in search.c: SearchObjectByID. * * MoveObject() is better as in aligntext(), but we * didn't keep the element reference when sorting. * */ MOVE_TEXT_LOWLEVEL(text, dx, dy); AddObjectToMoveUndoList(type, NULL, NULL, text, dx, dy); changed = 1; } /* in gaps mode, accumulate part widths */ if (point == K_Gaps) { /* move remaining half of our text */ s += texts_by_pos[i].width / 2; /* move half of next text */ if (i < ntexts_by_pos - 1) s += texts_by_pos[i + 1].width / 2; } } if (changed) { RestoreUndoSerialNumber(); IncrementUndoSerialNumber(); Redraw(); SetChangedFlag(true); } free_texts_by_pos(); return 0; }