1325 lines
49 KiB
C
1325 lines
49 KiB
C
/* File: move.c
|
|
*
|
|
* This file is part of XSCHEM,
|
|
* a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit
|
|
* simulation.
|
|
* Copyright (C) 1998-2023 Stefan Frederik Schippers
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "xschem.h"
|
|
|
|
void rebuild_selected_array() /* can be used only if new selected set is lower */
|
|
/* that is, xctx->sel_array[] size can not increase */
|
|
{
|
|
int i,c;
|
|
|
|
dbg(2, "rebuild selected array\n");
|
|
if(!xctx->need_reb_sel_arr) return;
|
|
xctx->lastsel=0;
|
|
for(i=0;i<xctx->texts; ++i)
|
|
if(xctx->text[i].sel)
|
|
{
|
|
check_selected_storage();
|
|
xctx->sel_array[xctx->lastsel].type = xTEXT;
|
|
xctx->sel_array[xctx->lastsel].n = i;
|
|
xctx->sel_array[xctx->lastsel++].col = TEXTLAYER;
|
|
}
|
|
for(i=0;i<xctx->instances; ++i)
|
|
if(xctx->inst[i].sel)
|
|
{
|
|
check_selected_storage();
|
|
xctx->sel_array[xctx->lastsel].type = ELEMENT;
|
|
xctx->sel_array[xctx->lastsel].n = i;
|
|
xctx->sel_array[xctx->lastsel++].col = WIRELAYER;
|
|
}
|
|
for(i=0;i<xctx->wires; ++i)
|
|
if(xctx->wire[i].sel)
|
|
{
|
|
check_selected_storage();
|
|
xctx->sel_array[xctx->lastsel].type = WIRE;
|
|
xctx->sel_array[xctx->lastsel].n = i;
|
|
xctx->sel_array[xctx->lastsel++].col = WIRELAYER;
|
|
}
|
|
for(c=0;c<cadlayers; ++c)
|
|
{
|
|
for(i=0;i<xctx->arcs[c]; ++i)
|
|
if(xctx->arc[c][i].sel)
|
|
{
|
|
check_selected_storage();
|
|
xctx->sel_array[xctx->lastsel].type = ARC;
|
|
xctx->sel_array[xctx->lastsel].n = i;
|
|
xctx->sel_array[xctx->lastsel++].col = c;
|
|
}
|
|
for(i=0;i<xctx->rects[c]; ++i)
|
|
if(xctx->rect[c][i].sel)
|
|
{
|
|
check_selected_storage();
|
|
xctx->sel_array[xctx->lastsel].type = xRECT;
|
|
xctx->sel_array[xctx->lastsel].n = i;
|
|
xctx->sel_array[xctx->lastsel++].col = c;
|
|
}
|
|
for(i=0;i<xctx->lines[c]; ++i)
|
|
if(xctx->line[c][i].sel)
|
|
{
|
|
check_selected_storage();
|
|
xctx->sel_array[xctx->lastsel].type = LINE;
|
|
xctx->sel_array[xctx->lastsel].n = i;
|
|
xctx->sel_array[xctx->lastsel++].col = c;
|
|
}
|
|
for(i=0;i<xctx->polygons[c]; ++i)
|
|
if(xctx->poly[c][i].sel)
|
|
{
|
|
check_selected_storage();
|
|
xctx->sel_array[xctx->lastsel].type = POLYGON;
|
|
xctx->sel_array[xctx->lastsel].n = i;
|
|
xctx->sel_array[xctx->lastsel++].col = c;
|
|
}
|
|
}
|
|
if(xctx->lastsel==0) {
|
|
xctx->ui_state &= ~SELECTION;
|
|
set_first_sel(0, -1, 0);
|
|
} else xctx->ui_state |= SELECTION;
|
|
xctx->need_reb_sel_arr=0;
|
|
}
|
|
|
|
void check_collapsing_objects()
|
|
{
|
|
int j,i, c;
|
|
int found=0;
|
|
|
|
j=0;
|
|
for(i=0;i<xctx->wires; ++i)
|
|
{
|
|
if(xctx->wire[i].x1==xctx->wire[i].x2 && xctx->wire[i].y1 == xctx->wire[i].y2)
|
|
{
|
|
my_free(_ALLOC_ID_, &xctx->wire[i].prop_ptr);
|
|
my_free(_ALLOC_ID_, &xctx->wire[i].node);
|
|
found=1;
|
|
++j;
|
|
continue;
|
|
}
|
|
if(j)
|
|
{
|
|
xctx->wire[i-j] = xctx->wire[i];
|
|
}
|
|
}
|
|
xctx->wires -= j;
|
|
|
|
/* option: remove degenerated lines */
|
|
for(c=0;c<cadlayers; ++c)
|
|
{
|
|
j = 0;
|
|
for(i=0;i<xctx->lines[c]; ++i)
|
|
{
|
|
if(xctx->line[c][i].x1==xctx->line[c][i].x2 && xctx->line[c][i].y1 == xctx->line[c][i].y2)
|
|
{
|
|
my_free(_ALLOC_ID_, &xctx->line[c][i].prop_ptr);
|
|
found=1;
|
|
++j;
|
|
continue;
|
|
}
|
|
if(j)
|
|
{
|
|
xctx->line[c][i-j] = xctx->line[c][i];
|
|
}
|
|
}
|
|
xctx->lines[c] -= j;
|
|
}
|
|
for(c=0;c<cadlayers; ++c)
|
|
{
|
|
j = 0;
|
|
for(i=0;i<xctx->rects[c]; ++i)
|
|
{
|
|
if(xctx->rect[c][i].x1==xctx->rect[c][i].x2 || xctx->rect[c][i].y1 == xctx->rect[c][i].y2)
|
|
{
|
|
my_free(_ALLOC_ID_, &xctx->rect[c][i].prop_ptr);
|
|
set_rect_extraptr(0, &xctx->rect[c][i]);
|
|
found=1;
|
|
++j;
|
|
continue;
|
|
}
|
|
if(j)
|
|
{
|
|
xctx->rect[c][i-j] = xctx->rect[c][i];
|
|
}
|
|
}
|
|
xctx->rects[c] -= j;
|
|
}
|
|
|
|
if(found) {
|
|
xctx->need_reb_sel_arr=1;
|
|
rebuild_selected_array();
|
|
}
|
|
}
|
|
|
|
static void update_symbol_bboxes(short rot, short flip)
|
|
{
|
|
int i, n;
|
|
short save_flip, save_rot;
|
|
|
|
for(i=0;i<xctx->movelastsel; ++i)
|
|
{
|
|
n = xctx->sel_array[i].n;
|
|
dbg(1, "update_symbol_bboxes(): i=%d, movelastsel=%d, n=%d\n", i, xctx->movelastsel, n);
|
|
if(xctx->sel_array[i].type == ELEMENT) {
|
|
dbg(1, "update_symbol_bboxes(): symbol flip=%d, rot=%d\n", xctx->inst[n].flip, xctx->inst[n].rot);
|
|
save_flip = xctx->inst[n].flip;
|
|
save_rot = xctx->inst[n].rot;
|
|
xctx->inst[n].flip = flip ^ xctx->inst[n].flip;
|
|
xctx->inst[n].rot = (xctx->inst[n].rot + rot) & 0x3;
|
|
symbol_bbox(n, &xctx->inst[n].x1, &xctx->inst[n].y1, &xctx->inst[n].x2, &xctx->inst[n].y2 );
|
|
xctx->inst[n].rot = save_rot;
|
|
xctx->inst[n].flip = save_flip;
|
|
}
|
|
}
|
|
}
|
|
|
|
void draw_selection(GC g, int interruptable)
|
|
{
|
|
int i, c, k, n;
|
|
double angle; /* arc */
|
|
#if HAS_CAIRO==1
|
|
int customfont;
|
|
#endif
|
|
dbg(1,"draw_selection %s\n", g == xctx->gctiled ? "gctiled" : "gcselect");
|
|
if(g != xctx->gctiled) xctx->movelastsel = xctx->lastsel;
|
|
|
|
if((fix_broken_tiled_fill || !_unix) && g == xctx->gctiled && xctx->movelastsel > 800) {
|
|
MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], xctx->xrect[0].x, xctx->xrect[0].y,
|
|
xctx->xrect[0].width, xctx->xrect[0].height, xctx->xrect[0].x, xctx->xrect[0].y);
|
|
return;
|
|
}
|
|
for(i=0;i<xctx->movelastsel; ++i)
|
|
{
|
|
short int tmp_rot;
|
|
c = xctx->sel_array[i].col;n = xctx->sel_array[i].n;
|
|
switch(xctx->sel_array[i].type)
|
|
{
|
|
case xTEXT:
|
|
if(xctx->rotatelocal) {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->text[n].x0, xctx->text[n].y0,
|
|
xctx->text[n].x0, xctx->text[n].y0, xctx->rx1,xctx->ry1);
|
|
} else {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
xctx->text[n].x0, xctx->text[n].y0, xctx->rx1,xctx->ry1);
|
|
}
|
|
#if HAS_CAIRO==1
|
|
customfont = set_text_custom_font(&xctx->text[n]);
|
|
#endif
|
|
draw_temp_string(g,ADD, get_text_floater(n),
|
|
(xctx->text[n].rot +
|
|
( (xctx->move_flip && (xctx->text[n].rot & 1) ) ? xctx->move_rot+2 : xctx->move_rot) ) & 0x3,
|
|
xctx->text[n].flip^xctx->move_flip, xctx->text[n].hcenter, xctx->text[n].vcenter,
|
|
xctx->rx1+xctx->deltax, xctx->ry1+xctx->deltay,
|
|
xctx->text[n].xscale, xctx->text[n].yscale);
|
|
#if HAS_CAIRO==1
|
|
if(customfont) {
|
|
cairo_restore(xctx->cairo_ctx);
|
|
}
|
|
#endif
|
|
|
|
break;
|
|
case xRECT:
|
|
if(xctx->rotatelocal) {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->rect[c][n].x1, xctx->rect[c][n].y1,
|
|
xctx->rect[c][n].x1, xctx->rect[c][n].y1, xctx->rx1,xctx->ry1);
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->rect[c][n].x1, xctx->rect[c][n].y1,
|
|
xctx->rect[c][n].x2, xctx->rect[c][n].y2, xctx->rx2,xctx->ry2);
|
|
} else {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
xctx->rect[c][n].x1, xctx->rect[c][n].y1, xctx->rx1,xctx->ry1);
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
xctx->rect[c][n].x2, xctx->rect[c][n].y2, xctx->rx2,xctx->ry2);
|
|
}
|
|
if(xctx->rect[c][n].sel==SELECTED)
|
|
{
|
|
RECTORDER(xctx->rx1,xctx->ry1,xctx->rx2,xctx->ry2);
|
|
drawtemprect(g, ADD, xctx->rx1+xctx->deltax, xctx->ry1+xctx->deltay,
|
|
xctx->rx2+xctx->deltax, xctx->ry2+xctx->deltay);
|
|
}
|
|
else if(xctx->rect[c][n].sel==SELECTED1)
|
|
{
|
|
xctx->rx1+=xctx->deltax;
|
|
xctx->ry1+=xctx->deltay;
|
|
RECTORDER(xctx->rx1,xctx->ry1,xctx->rx2,xctx->ry2);
|
|
drawtemprect(g, ADD, xctx->rx1, xctx->ry1, xctx->rx2, xctx->ry2);
|
|
}
|
|
else if(xctx->rect[c][n].sel==SELECTED2)
|
|
{
|
|
xctx->rx2+=xctx->deltax;
|
|
xctx->ry1+=xctx->deltay;
|
|
RECTORDER(xctx->rx1,xctx->ry1,xctx->rx2,xctx->ry2);
|
|
drawtemprect(g, ADD, xctx->rx1, xctx->ry1, xctx->rx2, xctx->ry2);
|
|
}
|
|
else if(xctx->rect[c][n].sel==SELECTED3)
|
|
{
|
|
xctx->rx1+=xctx->deltax;
|
|
xctx->ry2+=xctx->deltay;
|
|
RECTORDER(xctx->rx1,xctx->ry1,xctx->rx2,xctx->ry2);
|
|
drawtemprect(g, ADD, xctx->rx1, xctx->ry1, xctx->rx2, xctx->ry2);
|
|
}
|
|
else if(xctx->rect[c][n].sel==SELECTED4)
|
|
{
|
|
xctx->rx2+=xctx->deltax;
|
|
xctx->ry2+=xctx->deltay;
|
|
RECTORDER(xctx->rx1,xctx->ry1,xctx->rx2,xctx->ry2);
|
|
drawtemprect(g, ADD, xctx->rx1, xctx->ry1, xctx->rx2, xctx->ry2);
|
|
}
|
|
else if(xctx->rect[c][n].sel==(SELECTED1|SELECTED2))
|
|
{
|
|
xctx->ry1+=xctx->deltay;
|
|
RECTORDER(xctx->rx1,xctx->ry1,xctx->rx2,xctx->ry2);
|
|
drawtemprect(g, ADD, xctx->rx1, xctx->ry1, xctx->rx2, xctx->ry2);
|
|
}
|
|
else if(xctx->rect[c][n].sel==(SELECTED3|SELECTED4))
|
|
{
|
|
xctx->ry2+=xctx->deltay;
|
|
RECTORDER(xctx->rx1,xctx->ry1,xctx->rx2,xctx->ry2);
|
|
drawtemprect(g, ADD, xctx->rx1, xctx->ry1, xctx->rx2, xctx->ry2);
|
|
}
|
|
else if(xctx->rect[c][n].sel==(SELECTED1|SELECTED3))
|
|
{
|
|
xctx->rx1+=xctx->deltax;
|
|
RECTORDER(xctx->rx1,xctx->ry1,xctx->rx2,xctx->ry2);
|
|
drawtemprect(g, ADD, xctx->rx1, xctx->ry1, xctx->rx2, xctx->ry2);
|
|
}
|
|
else if(xctx->rect[c][n].sel==(SELECTED2|SELECTED4))
|
|
{
|
|
xctx->rx2+=xctx->deltax;
|
|
RECTORDER(xctx->rx1,xctx->ry1,xctx->rx2,xctx->ry2);
|
|
drawtemprect(g, ADD, xctx->rx1, xctx->ry1, xctx->rx2, xctx->ry2);
|
|
}
|
|
break;
|
|
case POLYGON:
|
|
{
|
|
int bezier;
|
|
double *x = my_malloc(_ALLOC_ID_, sizeof(double) *xctx->poly[c][n].points);
|
|
double *y = my_malloc(_ALLOC_ID_, sizeof(double) *xctx->poly[c][n].points);
|
|
bezier = 2 + !strboolcmp(get_tok_value(xctx->poly[c][n].prop_ptr, "bezier", 0), "true");
|
|
if(xctx->poly[c][n].sel==SELECTED || xctx->poly[c][n].sel==SELECTED1) {
|
|
for(k=0;k<xctx->poly[c][n].points; ++k) {
|
|
if( xctx->poly[c][n].sel==SELECTED || xctx->poly[c][n].selected_point[k]) {
|
|
if(xctx->rotatelocal) {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->poly[c][n].x[0], xctx->poly[c][n].y[0],
|
|
xctx->poly[c][n].x[k], xctx->poly[c][n].y[k], xctx->rx1,xctx->ry1);
|
|
} else {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
xctx->poly[c][n].x[k], xctx->poly[c][n].y[k], xctx->rx1,xctx->ry1);
|
|
}
|
|
x[k] = xctx->rx1 + xctx->deltax;
|
|
y[k] = xctx->ry1 + xctx->deltay;
|
|
} else {
|
|
x[k] = xctx->poly[c][n].x[k];
|
|
y[k] = xctx->poly[c][n].y[k];
|
|
}
|
|
}
|
|
drawtemppolygon(g, NOW, x, y, xctx->poly[c][n].points, bezier);
|
|
}
|
|
my_free(_ALLOC_ID_, &x);
|
|
my_free(_ALLOC_ID_, &y);
|
|
}
|
|
break;
|
|
|
|
case WIRE:
|
|
if(xctx->rotatelocal) {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->wire[n].x1, xctx->wire[n].y1,
|
|
xctx->wire[n].x1, xctx->wire[n].y1, xctx->rx1,xctx->ry1);
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->wire[n].x1, xctx->wire[n].y1,
|
|
xctx->wire[n].x2, xctx->wire[n].y2, xctx->rx2,xctx->ry2);
|
|
} else {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
xctx->wire[n].x1, xctx->wire[n].y1, xctx->rx1,xctx->ry1);
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
xctx->wire[n].x2, xctx->wire[n].y2, xctx->rx2,xctx->ry2);
|
|
}
|
|
|
|
ORDER(xctx->rx1,xctx->ry1,xctx->rx2,xctx->ry2);
|
|
if(xctx->wire[n].sel==SELECTED)
|
|
{
|
|
if(xctx->wire[n].bus)
|
|
drawtempline(g, THICK, xctx->rx1+xctx->deltax, xctx->ry1+xctx->deltay,
|
|
xctx->rx2+xctx->deltax, xctx->ry2+xctx->deltay);
|
|
else
|
|
drawtempline(g, ADD, xctx->rx1+xctx->deltax, xctx->ry1+xctx->deltay,
|
|
xctx->rx2+xctx->deltax, xctx->ry2+xctx->deltay);
|
|
}
|
|
else if(xctx->wire[n].sel==SELECTED1)
|
|
{
|
|
if(xctx->wire[n].bus)
|
|
drawtempline(g, THICK, xctx->rx1+xctx->deltax, xctx->ry1+xctx->deltay, xctx->rx2, xctx->ry2);
|
|
else
|
|
drawtempline(g, ADD, xctx->rx1+xctx->deltax, xctx->ry1+xctx->deltay, xctx->rx2, xctx->ry2);
|
|
}
|
|
else if(xctx->wire[n].sel==SELECTED2)
|
|
{
|
|
if(xctx->wire[n].bus)
|
|
drawtempline(g, THICK, xctx->rx1, xctx->ry1, xctx->rx2+xctx->deltax, xctx->ry2+xctx->deltay);
|
|
else
|
|
drawtempline(g, ADD, xctx->rx1, xctx->ry1, xctx->rx2+xctx->deltax, xctx->ry2+xctx->deltay);
|
|
}
|
|
break;
|
|
case LINE:
|
|
if(xctx->rotatelocal) {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->line[c][n].x1, xctx->line[c][n].y1,
|
|
xctx->line[c][n].x1, xctx->line[c][n].y1, xctx->rx1,xctx->ry1);
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->line[c][n].x1, xctx->line[c][n].y1,
|
|
xctx->line[c][n].x2, xctx->line[c][n].y2, xctx->rx2,xctx->ry2);
|
|
} else {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
xctx->line[c][n].x1, xctx->line[c][n].y1, xctx->rx1,xctx->ry1);
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
xctx->line[c][n].x2, xctx->line[c][n].y2, xctx->rx2,xctx->ry2);
|
|
}
|
|
ORDER(xctx->rx1,xctx->ry1,xctx->rx2,xctx->ry2);
|
|
if(xctx->line[c][n].sel==SELECTED)
|
|
{
|
|
if(xctx->line[c][n].bus)
|
|
drawtempline(g, THICK, xctx->rx1+xctx->deltax, xctx->ry1+xctx->deltay,
|
|
xctx->rx2+xctx->deltax, xctx->ry2+xctx->deltay);
|
|
else
|
|
drawtempline(g, ADD, xctx->rx1+xctx->deltax, xctx->ry1+xctx->deltay,
|
|
xctx->rx2+xctx->deltax, xctx->ry2+xctx->deltay);
|
|
}
|
|
else if(xctx->line[c][n].sel==SELECTED1)
|
|
{
|
|
if(xctx->line[c][n].bus)
|
|
drawtempline(g, THICK, xctx->rx1+xctx->deltax, xctx->ry1+xctx->deltay, xctx->rx2, xctx->ry2);
|
|
else
|
|
drawtempline(g, ADD, xctx->rx1+xctx->deltax, xctx->ry1+xctx->deltay, xctx->rx2, xctx->ry2);
|
|
}
|
|
else if(xctx->line[c][n].sel==SELECTED2)
|
|
{
|
|
if(xctx->line[c][n].bus)
|
|
drawtempline(g, THICK, xctx->rx1, xctx->ry1, xctx->rx2+xctx->deltax, xctx->ry2+xctx->deltay);
|
|
else
|
|
drawtempline(g, ADD, xctx->rx1, xctx->ry1, xctx->rx2+xctx->deltax, xctx->ry2+xctx->deltay);
|
|
}
|
|
break;
|
|
case ARC:
|
|
if(xctx->rotatelocal) {
|
|
/* rotate center wrt itself: do nothing */
|
|
xctx->rx1 = xctx->arc[c][n].x;
|
|
xctx->ry1 = xctx->arc[c][n].y;
|
|
} else {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
xctx->arc[c][n].x, xctx->arc[c][n].y, xctx->rx1,xctx->ry1);
|
|
}
|
|
angle = xctx->arc[c][n].a;
|
|
if(xctx->move_flip) {
|
|
angle = 270.*xctx->move_rot+180.-xctx->arc[c][n].b-xctx->arc[c][n].a;
|
|
} else {
|
|
angle = xctx->arc[c][n].a+xctx->move_rot*270.;
|
|
}
|
|
angle = fmod(angle, 360.);
|
|
if(angle<0.) angle+=360.;
|
|
if(xctx->arc[c][n].sel==SELECTED) {
|
|
drawtemparc(g, ADD, xctx->rx1+xctx->deltax, xctx->ry1+xctx->deltay,
|
|
xctx->arc[c][n].r, angle, xctx->arc[c][n].b);
|
|
} else if(xctx->arc[c][n].sel==SELECTED1) {
|
|
drawtemparc(g, ADD, xctx->rx1, xctx->ry1,
|
|
fabs(xctx->arc[c][n].r+xctx->deltax), angle, xctx->arc[c][n].b);
|
|
} else if(xctx->arc[c][n].sel==SELECTED3) {
|
|
angle = my_round(fmod(atan2(-xctx->deltay, xctx->deltax)*180./XSCH_PI+xctx->arc[c][n].b, 360.));
|
|
if(angle<0.) angle +=360.;
|
|
if(angle==0) angle=360.;
|
|
drawtemparc(g, ADD, xctx->rx1, xctx->ry1, xctx->arc[c][n].r, xctx->arc[c][n].a, angle);
|
|
} else if(xctx->arc[c][n].sel==SELECTED2) {
|
|
angle = my_round(fmod(atan2(-xctx->deltay, xctx->deltax)*180./XSCH_PI+angle, 360.));
|
|
if(angle<0.) angle +=360.;
|
|
drawtemparc(g, ADD, xctx->rx1, xctx->ry1, xctx->arc[c][n].r, angle, xctx->arc[c][n].b);
|
|
}
|
|
break;
|
|
case ELEMENT:
|
|
if(xctx->rotatelocal) {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->inst[n].x0, xctx->inst[n].y0,
|
|
xctx->inst[n].x0, xctx->inst[n].y0, xctx->rx1,xctx->ry1);
|
|
} else {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
xctx->inst[n].x0, xctx->inst[n].y0, xctx->rx1,xctx->ry1);
|
|
}
|
|
tmp_rot = (xctx->move_flip & xctx->inst[n].rot & 1) ?
|
|
0x3 & (xctx->move_rot + 2) : xctx->move_rot;
|
|
for(k=0;k<cadlayers; ++k) {
|
|
draw_temp_symbol(ADD, g, n, k, xctx->move_flip,
|
|
tmp_rot,
|
|
xctx->rx1-xctx->inst[n].x0+xctx->deltax,xctx->ry1-xctx->inst[n].y0+xctx->deltay);
|
|
}
|
|
break;
|
|
}
|
|
#ifdef __unix__
|
|
if(pending_events() && interruptable)
|
|
{
|
|
drawtemparc(g, END, 0.0, 0.0, 0.0, 0.0, 0.0);
|
|
drawtemprect(g, END, 0.0, 0.0, 0.0, 0.0);
|
|
drawtempline(g, END, 0.0, 0.0, 0.0, 0.0);
|
|
xctx->movelastsel = i+1;
|
|
return;
|
|
}
|
|
#else
|
|
if (interruptable)
|
|
{
|
|
drawtemparc(g, END, 0.0, 0.0, 0.0, 0.0, 0.0);
|
|
drawtemprect(g, END, 0.0, 0.0, 0.0, 0.0);
|
|
drawtempline(g, END, 0.0, 0.0, 0.0, 0.0);
|
|
xctx->movelastsel = i + 1;
|
|
return;
|
|
}
|
|
#endif
|
|
} /* for(i=0;i<xctx->movelastsel; ++i) */
|
|
drawtemparc(g, END, 0.0, 0.0, 0.0, 0.0, 0.0);
|
|
drawtemprect(g, END, 0.0, 0.0, 0.0, 0.0);
|
|
drawtempline(g, END, 0.0, 0.0, 0.0, 0.0);
|
|
xctx->movelastsel = i;
|
|
}
|
|
|
|
void copy_objects(int what)
|
|
{
|
|
int tmpi, c, i, n, k /*, tmp */ ;
|
|
double angle, dtmp;
|
|
int newpropcnt;
|
|
double tmpx, tmpy;
|
|
|
|
#if HAS_CAIRO==1
|
|
int customfont;
|
|
#endif
|
|
|
|
if(what & START)
|
|
{
|
|
xctx->rotatelocal=0;
|
|
dbg(1, "copy_objects(): START copy\n");
|
|
rebuild_selected_array();
|
|
update_symbol_bboxes(0, 0);
|
|
if(xctx->connect_by_kissing == 2) xctx->kissing = connect_by_kissing();
|
|
else xctx->kissing = 0;
|
|
|
|
save_selection(1);
|
|
xctx->deltax = xctx->deltay = 0.0;
|
|
xctx->movelastsel = xctx->lastsel;
|
|
xctx->x1=xctx->mousex_snap;xctx->y_1=xctx->mousey_snap;
|
|
xctx->move_flip = 0;xctx->move_rot = 0;
|
|
xctx->ui_state|=STARTCOPY;
|
|
}
|
|
if(what & ABORT) /* draw objects while moving */
|
|
{
|
|
draw_selection(xctx->gctiled,0);
|
|
|
|
if(xctx->kissing) {
|
|
pop_undo(0, 0);
|
|
if(xctx->connect_by_kissing == 2) xctx->connect_by_kissing = 0;
|
|
}
|
|
|
|
xctx->move_rot = xctx->move_flip = 0;
|
|
xctx->deltax = xctx->deltay = 0.;
|
|
xctx->ui_state&=~STARTCOPY;
|
|
update_symbol_bboxes(0, 0);
|
|
}
|
|
if(what & RUBBER) /* draw objects while moving */
|
|
{
|
|
xctx->x2=xctx->mousex_snap;xctx->y_2=xctx->mousey_snap;
|
|
draw_selection(xctx->gctiled,0);
|
|
xctx->deltax = xctx->x2-xctx->x1; xctx->deltay = xctx->y_2 - xctx->y_1;
|
|
}
|
|
if(what & ROTATELOCAL ) {
|
|
xctx->rotatelocal=1;
|
|
}
|
|
if(what & ROTATE) {
|
|
draw_selection(xctx->gctiled,0);
|
|
xctx->move_rot= (xctx->move_rot+1) & 0x3;
|
|
update_symbol_bboxes(xctx->move_rot, xctx->move_flip);
|
|
}
|
|
if(what & FLIP)
|
|
{
|
|
draw_selection(xctx->gctiled,0);
|
|
xctx->move_flip = !xctx->move_flip;
|
|
update_symbol_bboxes(xctx->move_rot, xctx->move_flip);
|
|
}
|
|
if(what & END) /* copy selected objects */
|
|
{
|
|
int l, firstw, firsti;
|
|
|
|
dbg(1, "end copy: unlink sel_file\n");
|
|
xunlink(sel_file);
|
|
set_first_sel(0, -1, 0); /* reset first selected object */
|
|
if(xctx->connect_by_kissing == 2) xctx->connect_by_kissing = 0;
|
|
|
|
newpropcnt=0;
|
|
|
|
if( !xctx->kissing ) {
|
|
dbg(1, "copy_objects(): push undo state\n");
|
|
xctx->push_undo();
|
|
}
|
|
|
|
firstw = firsti = 1;
|
|
|
|
|
|
/* button released after clicking elements, without moving... do nothing */
|
|
if(xctx->drag_elements && xctx->deltax==0 && xctx->deltay == 0) {
|
|
xctx->ui_state &= ~STARTCOPY;
|
|
return;
|
|
}
|
|
|
|
draw_selection(xctx->gctiled,0);
|
|
update_symbol_bboxes(0, 0);
|
|
|
|
for(i=0;i<xctx->lastsel; ++i)
|
|
{
|
|
n = xctx->sel_array[i].n;
|
|
if(xctx->sel_array[i].type == WIRE)
|
|
{
|
|
xctx->prep_hash_wires=0;
|
|
firstw = 0;
|
|
check_wire_storage();
|
|
if(xctx->rotatelocal) {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->wire[n].x1, xctx->wire[n].y1,
|
|
xctx->wire[n].x1, xctx->wire[n].y1, xctx->rx1,xctx->ry1);
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->wire[n].x1, xctx->wire[n].y1,
|
|
xctx->wire[n].x2, xctx->wire[n].y2, xctx->rx2,xctx->ry2);
|
|
} else {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
xctx->wire[n].x1, xctx->wire[n].y1, xctx->rx1,xctx->ry1);
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
xctx->wire[n].x2, xctx->wire[n].y2, xctx->rx2,xctx->ry2);
|
|
}
|
|
if( xctx->wire[n].sel & (SELECTED|SELECTED1) )
|
|
{
|
|
xctx->rx1+=xctx->deltax;
|
|
xctx->ry1+=xctx->deltay;
|
|
}
|
|
if( xctx->wire[n].sel & (SELECTED|SELECTED2) )
|
|
{
|
|
xctx->rx2+=xctx->deltax;
|
|
xctx->ry2+=xctx->deltay;
|
|
}
|
|
tmpx=xctx->rx1; /* used as temporary storage */
|
|
tmpy=xctx->ry1;
|
|
ORDER(xctx->rx1,xctx->ry1,xctx->rx2,xctx->ry2);
|
|
if( tmpx == xctx->rx2 && tmpy == xctx->ry2)
|
|
{
|
|
if(xctx->wire[n].sel == SELECTED1) xctx->wire[n].sel = SELECTED2;
|
|
else if(xctx->wire[n].sel == SELECTED2) xctx->wire[n].sel = SELECTED1;
|
|
}
|
|
xctx->sel_array[i].n=xctx->wires;
|
|
storeobject(-1, xctx->rx1,xctx->ry1,xctx->rx2,xctx->ry2,WIRE,0,xctx->wire[n].sel,xctx->wire[n].prop_ptr);
|
|
xctx->wire[n].sel=0;
|
|
|
|
l = xctx->wires -1;
|
|
}
|
|
}
|
|
|
|
for(k=0;k<cadlayers; ++k)
|
|
{
|
|
for(i=0;i<xctx->lastsel; ++i)
|
|
{
|
|
c = xctx->sel_array[i].col;n = xctx->sel_array[i].n;
|
|
switch(xctx->sel_array[i].type)
|
|
{
|
|
case LINE:
|
|
if(c!=k) break;
|
|
if(xctx->rotatelocal) {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->line[c][n].x1, xctx->line[c][n].y1,
|
|
xctx->line[c][n].x1, xctx->line[c][n].y1, xctx->rx1,xctx->ry1);
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->line[c][n].x1, xctx->line[c][n].y1,
|
|
xctx->line[c][n].x2, xctx->line[c][n].y2, xctx->rx2,xctx->ry2);
|
|
} else {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
xctx->line[c][n].x1, xctx->line[c][n].y1, xctx->rx1,xctx->ry1);
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
xctx->line[c][n].x2, xctx->line[c][n].y2, xctx->rx2,xctx->ry2);
|
|
}
|
|
if( xctx->line[c][n].sel & (SELECTED|SELECTED1) )
|
|
{
|
|
xctx->rx1+=xctx->deltax;
|
|
xctx->ry1+=xctx->deltay;
|
|
}
|
|
if( xctx->line[c][n].sel & (SELECTED|SELECTED2) )
|
|
{
|
|
xctx->rx2+=xctx->deltax;
|
|
xctx->ry2+=xctx->deltay;
|
|
}
|
|
tmpx=xctx->rx1;
|
|
tmpy=xctx->ry1;
|
|
ORDER(xctx->rx1,xctx->ry1,xctx->rx2,xctx->ry2);
|
|
if( tmpx == xctx->rx2 && tmpy == xctx->ry2)
|
|
{
|
|
if(xctx->line[c][n].sel == SELECTED1) xctx->line[c][n].sel = SELECTED2;
|
|
else if(xctx->line[c][n].sel == SELECTED2) xctx->line[c][n].sel = SELECTED1;
|
|
}
|
|
xctx->sel_array[i].n=xctx->lines[c];
|
|
storeobject(-1, xctx->rx1, xctx->ry1, xctx->rx2, xctx->ry2, LINE, c,
|
|
xctx->line[c][n].sel, xctx->line[c][n].prop_ptr);
|
|
xctx->line[c][n].sel=0;
|
|
|
|
l = xctx->lines[c] - 1;
|
|
break;
|
|
|
|
case POLYGON:
|
|
if(c!=k) break;
|
|
{
|
|
xPoly *p = &xctx->poly[c][n];
|
|
double bx1 = 0.0, by1 = 0.0, bx2 = 0.0, by2 = 0.0;
|
|
double *x = my_malloc(_ALLOC_ID_, sizeof(double) *p->points);
|
|
double *y = my_malloc(_ALLOC_ID_, sizeof(double) *p->points);
|
|
int j;
|
|
for(j=0; j<p->points; ++j) {
|
|
if( p->sel==SELECTED || p->selected_point[j]) {
|
|
if(xctx->rotatelocal) {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, p->x[0], p->y[0], p->x[j], p->y[j], xctx->rx1,xctx->ry1);
|
|
} else {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1, p->x[j], p->y[j], xctx->rx1,xctx->ry1);
|
|
}
|
|
x[j] = xctx->rx1+xctx->deltax;
|
|
y[j] = xctx->ry1+xctx->deltay;
|
|
} else {
|
|
x[j] = p->x[j];
|
|
y[j] = p->y[j];
|
|
}
|
|
if(j==0 || x[j] < bx1) bx1 = x[j];
|
|
if(j==0 || y[j] < by1) by1 = y[j];
|
|
if(j==0 || x[j] > bx2) bx2 = x[j];
|
|
if(j==0 || y[j] > by2) by2 = y[j];
|
|
}
|
|
xctx->sel_array[i].n=xctx->polygons[c];
|
|
store_poly(-1, x, y, p->points, c, p->sel, p->prop_ptr);
|
|
p->sel=0;
|
|
my_free(_ALLOC_ID_, &x);
|
|
my_free(_ALLOC_ID_, &y);
|
|
}
|
|
break;
|
|
case ARC:
|
|
if(c!=k) break;
|
|
if(xctx->rotatelocal) {
|
|
/* rotate center wrt itself: do nothing */
|
|
xctx->rx1 = xctx->arc[c][n].x;
|
|
xctx->ry1 = xctx->arc[c][n].y;
|
|
} else {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
xctx->arc[c][n].x, xctx->arc[c][n].y, xctx->rx1,xctx->ry1);
|
|
}
|
|
angle = xctx->arc[c][n].a;
|
|
if(xctx->move_flip) {
|
|
angle = 270.*xctx->move_rot+180.-xctx->arc[c][n].b-xctx->arc[c][n].a;
|
|
} else {
|
|
angle = xctx->arc[c][n].a+xctx->move_rot*270.;
|
|
}
|
|
angle = fmod(angle, 360.);
|
|
if(angle<0.) angle+=360.;
|
|
xctx->arc[c][n].sel=0;
|
|
xctx->sel_array[i].n=xctx->arcs[c];
|
|
|
|
store_arc(-1, xctx->rx1+xctx->deltax, xctx->ry1+xctx->deltay,
|
|
xctx->arc[c][n].r, angle, xctx->arc[c][n].b, c, SELECTED, xctx->arc[c][n].prop_ptr);
|
|
|
|
l = xctx->arcs[c] - 1;
|
|
break;
|
|
|
|
case xRECT:
|
|
if(c!=k) break;
|
|
if(xctx->rotatelocal) {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->rect[c][n].x1, xctx->rect[c][n].y1,
|
|
xctx->rect[c][n].x1, xctx->rect[c][n].y1, xctx->rx1,xctx->ry1);
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->rect[c][n].x1, xctx->rect[c][n].y1,
|
|
xctx->rect[c][n].x2, xctx->rect[c][n].y2, xctx->rx2,xctx->ry2);
|
|
} else {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
xctx->rect[c][n].x1, xctx->rect[c][n].y1, xctx->rx1,xctx->ry1);
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
xctx->rect[c][n].x2, xctx->rect[c][n].y2, xctx->rx2,xctx->ry2);
|
|
}
|
|
RECTORDER(xctx->rx1,xctx->ry1,xctx->rx2,xctx->ry2);
|
|
xctx->rect[c][n].sel=0;
|
|
xctx->sel_array[i].n=xctx->rects[c];
|
|
/* following also clears extraptr */
|
|
storeobject(-1, xctx->rx1+xctx->deltax, xctx->ry1+xctx->deltay,
|
|
xctx->rx2+xctx->deltax, xctx->ry2+xctx->deltay,xRECT, c, SELECTED, xctx->rect[c][n].prop_ptr);
|
|
l = xctx->rects[c] - 1;
|
|
break;
|
|
|
|
case xTEXT:
|
|
if(k!=TEXTLAYER) break;
|
|
check_text_storage();
|
|
if(xctx->rotatelocal) {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->text[n].x0, xctx->text[n].y0,
|
|
xctx->text[n].x0, xctx->text[n].y0, xctx->rx1,xctx->ry1);
|
|
} else {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
xctx->text[n].x0, xctx->text[n].y0, xctx->rx1,xctx->ry1);
|
|
}
|
|
xctx->text[xctx->texts].txt_ptr=NULL;
|
|
my_strdup2(_ALLOC_ID_, &xctx->text[xctx->texts].txt_ptr,xctx->text[n].txt_ptr);
|
|
xctx->text[n].sel=0;
|
|
dbg(2, "copy_objects(): current str=%s\n",
|
|
xctx->text[xctx->texts].txt_ptr);
|
|
xctx->text[xctx->texts].x0=xctx->rx1+xctx->deltax;
|
|
xctx->text[xctx->texts].y0=xctx->ry1+xctx->deltay;
|
|
xctx->text[xctx->texts].rot=(xctx->text[n].rot +
|
|
( (xctx->move_flip && (xctx->text[n].rot & 1) ) ? xctx->move_rot+2 : xctx->move_rot) ) & 0x3;
|
|
xctx->text[xctx->texts].flip=xctx->move_flip^xctx->text[n].flip;
|
|
set_first_sel(xTEXT, xctx->texts, 0);
|
|
xctx->text[xctx->texts].sel=SELECTED;
|
|
xctx->text[xctx->texts].prop_ptr=NULL;
|
|
xctx->text[xctx->texts].font=NULL;
|
|
xctx->text[xctx->texts].floater_instname=NULL;
|
|
xctx->text[xctx->texts].floater_ptr=NULL;
|
|
my_strdup2(_ALLOC_ID_, &xctx->text[xctx->texts].prop_ptr, xctx->text[n].prop_ptr);
|
|
my_strdup2(_ALLOC_ID_, &xctx->text[xctx->texts].floater_ptr, xctx->text[n].floater_ptr);
|
|
my_strdup2(_ALLOC_ID_, &xctx->text[xctx->texts].floater_instname, xctx->text[n].floater_instname);
|
|
set_text_flags(&xctx->text[xctx->texts]);
|
|
xctx->text[xctx->texts].xscale=xctx->text[n].xscale;
|
|
xctx->text[xctx->texts].yscale=xctx->text[n].yscale;
|
|
|
|
l = xctx->texts;
|
|
|
|
#if HAS_CAIRO==1 /* bbox after copy */
|
|
customfont = set_text_custom_font(&xctx->text[l]);
|
|
#endif
|
|
text_bbox(get_text_floater(l), xctx->text[l].xscale,
|
|
xctx->text[l].yscale, xctx->text[l].rot,xctx->text[l].flip,
|
|
xctx->text[l].hcenter, xctx->text[l].vcenter,
|
|
xctx->text[l].x0, xctx->text[l].y0,
|
|
&xctx->rx1,&xctx->ry1, &xctx->rx2,&xctx->ry2, &tmpi, &dtmp);
|
|
#if HAS_CAIRO==1
|
|
if(customfont) {
|
|
cairo_restore(xctx->cairo_ctx);
|
|
}
|
|
#endif
|
|
|
|
xctx->sel_array[i].n=xctx->texts;
|
|
xctx->texts++;
|
|
dbg(2, "copy_objects(): done copy string\n");
|
|
break;
|
|
default:
|
|
break;
|
|
} /* end switch(xctx->sel_array[i].type) */
|
|
} /* end for(i=0;i<xctx->lastsel; ++i) */
|
|
|
|
|
|
} /* end for(k=0;k<cadlayers; ++k) */
|
|
|
|
for(i = 0; i < xctx->lastsel; ++i) {
|
|
n = xctx->sel_array[i].n;
|
|
if(xctx->sel_array[i].type == ELEMENT) {
|
|
xctx->prep_hash_inst = 0;
|
|
firsti = 0;
|
|
check_inst_storage();
|
|
if(xctx->rotatelocal) {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->inst[n].x0, xctx->inst[n].y0,
|
|
xctx->inst[n].x0, xctx->inst[n].y0, xctx->rx1,xctx->ry1);
|
|
} else {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
xctx->inst[n].x0, xctx->inst[n].y0, xctx->rx1,xctx->ry1);
|
|
}
|
|
xctx->inst[xctx->instances] = xctx->inst[n];
|
|
xctx->inst[xctx->instances].prop_ptr=NULL;
|
|
xctx->inst[xctx->instances].instname=NULL;
|
|
xctx->inst[xctx->instances].lab=NULL;
|
|
xctx->inst[xctx->instances].node=NULL;
|
|
xctx->inst[xctx->instances].name=NULL;
|
|
my_strdup2(_ALLOC_ID_, &xctx->inst[xctx->instances].name, xctx->inst[n].name);
|
|
my_strdup2(_ALLOC_ID_, &xctx->inst[xctx->instances].prop_ptr, xctx->inst[n].prop_ptr);
|
|
my_strdup2(_ALLOC_ID_, &xctx->inst[xctx->instances].lab, xctx->inst[n].lab);
|
|
xctx->inst[n].sel=0;
|
|
xctx->inst[xctx->instances].embed = xctx->inst[n].embed;
|
|
xctx->inst[xctx->instances].flags = xctx->inst[n].flags;
|
|
xctx->inst[xctx->instances].color = -10000;
|
|
xctx->inst[xctx->instances].x0 = xctx->rx1+xctx->deltax;
|
|
xctx->inst[xctx->instances].y0 = xctx->ry1+xctx->deltay;
|
|
set_first_sel(ELEMENT, xctx->instances, 0);
|
|
xctx->inst[xctx->instances].sel = SELECTED;
|
|
xctx->inst[xctx->instances].rot = (xctx->inst[xctx->instances].rot + ( (xctx->move_flip &&
|
|
(xctx->inst[xctx->instances].rot & 1) ) ? xctx->move_rot+2 : xctx->move_rot) ) & 0x3;
|
|
xctx->inst[xctx->instances].flip = (xctx->move_flip? !xctx->inst[n].flip:xctx->inst[n].flip);
|
|
my_strdup2(_ALLOC_ID_, &xctx->inst[xctx->instances].instname, xctx->inst[n].instname);
|
|
/* the newpropcnt argument is zero for the 1st call and used in */
|
|
/* new_prop_string() for cleaning some internal caches. */
|
|
if(!newpropcnt) hash_names(-1, XINSERT);
|
|
newpropcnt++;
|
|
new_prop_string(xctx->instances, xctx->inst[n].prop_ptr, /* sets also inst[].instname */
|
|
tclgetboolvar("disable_unique_names"));
|
|
hash_names(xctx->instances, XINSERT);
|
|
xctx->instances++; /* symbol_bbox calls translate and translate must have updated xctx->instances */
|
|
symbol_bbox(xctx->instances-1,
|
|
&xctx->inst[xctx->instances-1].x1, &xctx->inst[xctx->instances-1].y1,
|
|
&xctx->inst[xctx->instances-1].x2, &xctx->inst[xctx->instances-1].y2);
|
|
} /* if(xctx->sel_array[i].type == ELEMENT) */
|
|
} /* for(i = 0; i < xctx->lastsel; ++i) */
|
|
xctx->need_reb_sel_arr=1;
|
|
rebuild_selected_array();
|
|
if(!firsti || !firstw) {
|
|
xctx->prep_net_structs=0;
|
|
xctx->prep_hi_structs=0;
|
|
}
|
|
/* build after copying and after recalculating prepare_netlist_structs() */
|
|
check_collapsing_objects();
|
|
if(tclgetboolvar("autotrim_wires")) trim_wires();
|
|
if(xctx->hilight_nets) {
|
|
propagate_hilights(1, 1, XINSERT_NOREPLACE);
|
|
}
|
|
xctx->ui_state &= ~STARTCOPY;
|
|
xctx->x1 = xctx->y_1 = xctx->x2 = xctx->y_2 = xctx->deltax = xctx->deltay = 0;
|
|
xctx->move_rot = xctx->move_flip = 0;
|
|
set_modify(1); /* must be done before draw() if floaters are present to force cached values update */
|
|
draw();
|
|
xctx->rotatelocal=0;
|
|
} /* if(what & END) */
|
|
draw_selection(xctx->gc[SELLAYER], 0);
|
|
if(tclgetboolvar("draw_crosshair")) draw_crosshair(0);
|
|
}
|
|
|
|
|
|
/* merge param unused, RFU */
|
|
void move_objects(int what, int merge, double dx, double dy)
|
|
{
|
|
int c, i, n, k, tmpint;
|
|
double angle, dtmp;
|
|
double tx1,ty1; /* temporaries for swapping coordinates 20070302 */
|
|
#if HAS_CAIRO==1
|
|
int customfont;
|
|
#endif
|
|
xLine ** const line = xctx->line;
|
|
xWire * const wire = xctx->wire;
|
|
|
|
dbg(1, "move_objects: what=%d, dx=%g, dy=%g\n", what, dx, dy);
|
|
if(what & START)
|
|
{
|
|
xctx->rotatelocal=0;
|
|
xctx->deltax = xctx->deltay = 0.0;
|
|
rebuild_selected_array();
|
|
update_symbol_bboxes(0, 0);
|
|
/* if connect_by_kissing==2 it was set in callback.c ('M' command) */
|
|
if(xctx->connect_by_kissing == 2) xctx->kissing = connect_by_kissing();
|
|
else xctx->kissing = 0;
|
|
xctx->movelastsel = xctx->lastsel;
|
|
if(xctx->lastsel==1 && xctx->sel_array[0].type==ARC &&
|
|
xctx->arc[c=xctx->sel_array[0].col][n=xctx->sel_array[0].n].sel!=SELECTED) {
|
|
xctx->x1 = xctx->arc[c][n].x;
|
|
xctx->y_1 = xctx->arc[c][n].y;
|
|
} else {xctx->x1=xctx->mousex_snap;xctx->y_1=xctx->mousey_snap;}
|
|
xctx->move_flip = 0;xctx->move_rot = 0;
|
|
xctx->ui_state|=STARTMOVE;
|
|
}
|
|
if(what & ABORT) /* draw objects while moving */
|
|
{
|
|
xctx->paste_from = 0;
|
|
draw_selection(xctx->gctiled,0);
|
|
if(xctx->kissing) {
|
|
pop_undo(0, 0);
|
|
if(xctx->connect_by_kissing == 2) xctx->connect_by_kissing = 0;
|
|
}
|
|
|
|
xctx->move_rot=xctx->move_flip=0;
|
|
xctx->deltax=xctx->deltay=0.;
|
|
xctx->ui_state &= ~STARTMOVE;
|
|
update_symbol_bboxes(0, 0);
|
|
}
|
|
if(what & RUBBER) /* abort operation */
|
|
{
|
|
|
|
xctx->x2=xctx->mousex_snap;xctx->y_2=xctx->mousey_snap;
|
|
draw_selection(xctx->gctiled,0);
|
|
xctx->deltax = xctx->x2-xctx->x1; xctx->deltay = xctx->y_2 - xctx->y_1;
|
|
}
|
|
if(what & ROTATELOCAL) {
|
|
xctx->rotatelocal=1;
|
|
}
|
|
if(what & ROTATE) {
|
|
draw_selection(xctx->gctiled,0);
|
|
xctx->move_rot= (xctx->move_rot+1) & 0x3;
|
|
update_symbol_bboxes(xctx->move_rot, xctx->move_flip);
|
|
}
|
|
if(what & FLIP)
|
|
{
|
|
draw_selection(xctx->gctiled,0);
|
|
xctx->move_flip = !xctx->move_flip;
|
|
update_symbol_bboxes(xctx->move_rot, xctx->move_flip);
|
|
}
|
|
if(what & END) /* move selected objects */
|
|
{
|
|
int firsti, firstw;
|
|
|
|
dbg(1, "end move: unlink sel_file\n");
|
|
xunlink(sel_file);
|
|
xctx->paste_from = 0; /* end of a paste from clipboard command */
|
|
if(xctx->connect_by_kissing == 2) xctx->connect_by_kissing = 0;
|
|
/* no undo push for MERGE ad PLACE and polygon point drag, already done before */
|
|
if(!xctx->kissing &&
|
|
!(xctx->ui_state & (STARTMERGE | PLACE_SYMBOL | PLACE_TEXT)) ) {
|
|
dbg(1, "move_objects(END): push undo state\n");
|
|
xctx->push_undo();
|
|
}
|
|
if((xctx->ui_state & PLACE_SYMBOL)) {
|
|
int n = xctx->sel_array[0].n;
|
|
const char *f = abs_sym_path((xctx->inst[n].ptr+ xctx->sym)->name, "");
|
|
tclvareval("c_toolbar::add {",f, "}; c_toolbar::display", NULL);
|
|
}
|
|
xctx->ui_state &= ~PLACE_SYMBOL;
|
|
xctx->ui_state &= ~PLACE_TEXT;
|
|
if(dx!=0.0 || dy!=0.0) {
|
|
xctx->deltax = dx;
|
|
xctx->deltay = dy;
|
|
}
|
|
/* calculate moving symbols bboxes before actually doing the move */
|
|
firsti = firstw = 1;
|
|
/* button released after clicking elements, without moving... do nothing */
|
|
if(xctx->drag_elements && xctx->deltax==0 && xctx->deltay == 0) {
|
|
xctx->ui_state &= ~STARTMOVE;
|
|
return;
|
|
}
|
|
draw_selection(xctx->gctiled,0);
|
|
update_symbol_bboxes(0, 0);
|
|
for(k=0;k<cadlayers; ++k)
|
|
{
|
|
for(i=0;i<xctx->lastsel; ++i)
|
|
{
|
|
c = xctx->sel_array[i].col;n = xctx->sel_array[i].n;
|
|
switch(xctx->sel_array[i].type)
|
|
{
|
|
case WIRE:
|
|
xctx->prep_hash_wires=0;
|
|
firstw = 0;
|
|
if(k == 0) {
|
|
if(xctx->rotatelocal) {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, wire[n].x1, wire[n].y1,
|
|
wire[n].x1, wire[n].y1, xctx->rx1,xctx->ry1);
|
|
ROTATION(xctx->move_rot, xctx->move_flip, wire[n].x1, wire[n].y1,
|
|
wire[n].x2, wire[n].y2, xctx->rx2,xctx->ry2);
|
|
} else {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
wire[n].x1, wire[n].y1, xctx->rx1,xctx->ry1);
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
wire[n].x2, wire[n].y2, xctx->rx2,xctx->ry2);
|
|
}
|
|
if( wire[n].sel & (SELECTED|SELECTED1) )
|
|
{
|
|
xctx->rx1+=xctx->deltax;
|
|
xctx->ry1+=xctx->deltay;
|
|
}
|
|
if( wire[n].sel & (SELECTED|SELECTED2) )
|
|
{
|
|
xctx->rx2+=xctx->deltax;
|
|
xctx->ry2+=xctx->deltay;
|
|
}
|
|
wire[n].x1=xctx->rx1;
|
|
wire[n].y1=xctx->ry1;
|
|
ORDER(xctx->rx1,xctx->ry1,xctx->rx2,xctx->ry2);
|
|
if( wire[n].x1 == xctx->rx2 && wire[n].y1 == xctx->ry2)
|
|
{
|
|
if(wire[n].sel == SELECTED1) wire[n].sel = SELECTED2;
|
|
else if(wire[n].sel == SELECTED2) wire[n].sel = SELECTED1;
|
|
}
|
|
wire[n].x1=xctx->rx1;
|
|
wire[n].y1=xctx->ry1;
|
|
wire[n].x2=xctx->rx2;
|
|
wire[n].y2=xctx->ry2;
|
|
}
|
|
break;
|
|
|
|
case LINE:
|
|
if(c!=k) break;
|
|
if(xctx->rotatelocal) {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, line[c][n].x1, line[c][n].y1,
|
|
line[c][n].x1, line[c][n].y1, xctx->rx1,xctx->ry1);
|
|
ROTATION(xctx->move_rot, xctx->move_flip, line[c][n].x1, line[c][n].y1,
|
|
line[c][n].x2, line[c][n].y2, xctx->rx2,xctx->ry2);
|
|
} else {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
line[c][n].x1, line[c][n].y1, xctx->rx1,xctx->ry1);
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
line[c][n].x2, line[c][n].y2, xctx->rx2,xctx->ry2);
|
|
}
|
|
|
|
if( line[c][n].sel & (SELECTED|SELECTED1) )
|
|
{
|
|
xctx->rx1+=xctx->deltax;
|
|
xctx->ry1+=xctx->deltay;
|
|
}
|
|
if( line[c][n].sel & (SELECTED|SELECTED2) )
|
|
{
|
|
xctx->rx2+=xctx->deltax;
|
|
xctx->ry2+=xctx->deltay;
|
|
}
|
|
line[c][n].x1=xctx->rx1;
|
|
line[c][n].y1=xctx->ry1;
|
|
ORDER(xctx->rx1,xctx->ry1,xctx->rx2,xctx->ry2);
|
|
if( line[c][n].x1 == xctx->rx2 && line[c][n].y1 == xctx->ry2)
|
|
{
|
|
if(line[c][n].sel == SELECTED1) line[c][n].sel = SELECTED2;
|
|
else if(line[c][n].sel == SELECTED2) line[c][n].sel = SELECTED1;
|
|
}
|
|
line[c][n].x1=xctx->rx1;
|
|
line[c][n].y1=xctx->ry1;
|
|
line[c][n].x2=xctx->rx2;
|
|
line[c][n].y2=xctx->ry2;
|
|
break;
|
|
|
|
case POLYGON:
|
|
if(c!=k) break;
|
|
{
|
|
xPoly *p = &xctx->poly[c][n];
|
|
double bx1=0., by1=0., bx2=0., by2=0.;
|
|
int j;
|
|
double savex0, savey0;
|
|
savex0 = p->x[0];
|
|
savey0 = p->y[0];
|
|
for(j=0; j<p->points; ++j) {
|
|
if(j==0 || p->x[j] < bx1) bx1 = p->x[j];
|
|
if(j==0 || p->y[j] < by1) by1 = p->y[j];
|
|
if(j==0 || p->x[j] > bx2) bx2 = p->x[j];
|
|
if(j==0 || p->y[j] > by2) by2 = p->y[j];
|
|
|
|
if( p->sel==SELECTED || p->selected_point[j]) {
|
|
if(xctx->rotatelocal) {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, savex0, savey0, p->x[j], p->y[j],
|
|
xctx->rx1,xctx->ry1);
|
|
} else {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1, p->x[j], p->y[j],
|
|
xctx->rx1,xctx->ry1);
|
|
}
|
|
|
|
p->x[j] = xctx->rx1+xctx->deltax;
|
|
p->y[j] = xctx->ry1+xctx->deltay;
|
|
}
|
|
|
|
}
|
|
|
|
for(j=0; j<p->points; ++j) {
|
|
if(j==0 || p->x[j] < bx1) bx1 = p->x[j];
|
|
if(j==0 || p->y[j] < by1) by1 = p->y[j];
|
|
if(j==0 || p->x[j] > bx2) bx2 = p->x[j];
|
|
if(j==0 || p->y[j] > by2) by2 = p->y[j];
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ARC:
|
|
if(c!=k) break;
|
|
if(xctx->rotatelocal) {
|
|
/* rotate center wrt itself: do nothing */
|
|
xctx->rx1 = xctx->arc[c][n].x;
|
|
xctx->ry1 = xctx->arc[c][n].y;
|
|
} else {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
xctx->arc[c][n].x, xctx->arc[c][n].y, xctx->rx1,xctx->ry1);
|
|
}
|
|
angle = xctx->arc[c][n].a;
|
|
if(xctx->move_flip) {
|
|
angle = 270.*xctx->move_rot+180.-xctx->arc[c][n].b-xctx->arc[c][n].a;
|
|
} else {
|
|
angle = xctx->arc[c][n].a+xctx->move_rot*270.;
|
|
}
|
|
angle = fmod(angle, 360.);
|
|
if(angle<0.) angle+=360.;
|
|
if(xctx->arc[c][n].sel == SELECTED) {
|
|
xctx->arc[c][n].x = xctx->rx1+xctx->deltax;
|
|
xctx->arc[c][n].y = xctx->ry1+xctx->deltay;
|
|
xctx->arc[c][n].a = angle;
|
|
} else if(xctx->arc[c][n].sel == SELECTED1) {
|
|
xctx->arc[c][n].x = xctx->rx1;
|
|
xctx->arc[c][n].y = xctx->ry1;
|
|
if(xctx->arc[c][n].r+xctx->deltax) xctx->arc[c][n].r = fabs(xctx->arc[c][n].r+xctx->deltax);
|
|
xctx->arc[c][n].a = angle;
|
|
} else if(xctx->arc[c][n].sel == SELECTED2) {
|
|
angle = my_round(fmod(atan2(-xctx->deltay, xctx->deltax)*180./XSCH_PI+angle, 360.));
|
|
if(angle<0.) angle +=360.;
|
|
xctx->arc[c][n].x = xctx->rx1;
|
|
xctx->arc[c][n].y = xctx->ry1;
|
|
xctx->arc[c][n].a = angle;
|
|
} else if(xctx->arc[c][n].sel==SELECTED3) {
|
|
angle = my_round(fmod(atan2(-xctx->deltay, xctx->deltax)*180./XSCH_PI+xctx->arc[c][n].b, 360.));
|
|
if(angle<0.) angle +=360.;
|
|
if(angle==0) angle=360.;
|
|
xctx->arc[c][n].x = xctx->rx1;
|
|
xctx->arc[c][n].y = xctx->ry1;
|
|
xctx->arc[c][n].b = angle;
|
|
}
|
|
|
|
break;
|
|
|
|
case xRECT:
|
|
if(c!=k) break;
|
|
/* bbox before move */
|
|
if(xctx->rotatelocal) {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->rect[c][n].x1, xctx->rect[c][n].y1,
|
|
xctx->rect[c][n].x1, xctx->rect[c][n].y1, xctx->rx1,xctx->ry1);
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->rect[c][n].x1, xctx->rect[c][n].y1,
|
|
xctx->rect[c][n].x2, xctx->rect[c][n].y2, xctx->rx2,xctx->ry2);
|
|
} else {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
xctx->rect[c][n].x1, xctx->rect[c][n].y1, xctx->rx1,xctx->ry1);
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
xctx->rect[c][n].x2, xctx->rect[c][n].y2, xctx->rx2,xctx->ry2);
|
|
}
|
|
|
|
if( xctx->rect[c][n].sel == SELECTED) {
|
|
xctx->rx1+=xctx->deltax;
|
|
xctx->ry1+=xctx->deltay;
|
|
xctx->rx2+=xctx->deltax;
|
|
xctx->ry2+=xctx->deltay;
|
|
}
|
|
else if( xctx->rect[c][n].sel == SELECTED1) { /* 20070302 stretching on rectangles */
|
|
xctx->rx1+=xctx->deltax;
|
|
xctx->ry1+=xctx->deltay;
|
|
}
|
|
else if( xctx->rect[c][n].sel == SELECTED2) {
|
|
xctx->rx2+=xctx->deltax;
|
|
xctx->ry1+=xctx->deltay;
|
|
}
|
|
else if( xctx->rect[c][n].sel == SELECTED3) {
|
|
xctx->rx1+=xctx->deltax;
|
|
xctx->ry2+=xctx->deltay;
|
|
}
|
|
else if( xctx->rect[c][n].sel == SELECTED4) {
|
|
xctx->rx2+=xctx->deltax;
|
|
xctx->ry2+=xctx->deltay;
|
|
}
|
|
else if(xctx->rect[c][n].sel==(SELECTED1|SELECTED2))
|
|
{
|
|
xctx->ry1+=xctx->deltay;
|
|
}
|
|
else if(xctx->rect[c][n].sel==(SELECTED3|SELECTED4))
|
|
{
|
|
xctx->ry2+=xctx->deltay;
|
|
}
|
|
else if(xctx->rect[c][n].sel==(SELECTED1|SELECTED3))
|
|
{
|
|
xctx->rx1+=xctx->deltax;
|
|
}
|
|
else if(xctx->rect[c][n].sel==(SELECTED2|SELECTED4))
|
|
{
|
|
xctx->rx2+=xctx->deltax;
|
|
}
|
|
|
|
tx1 = xctx->rx1;
|
|
ty1 = xctx->ry1;
|
|
RECTORDER(xctx->rx1,xctx->ry1,xctx->rx2,xctx->ry2);
|
|
|
|
if( xctx->rx2 == tx1) {
|
|
if(xctx->rect[c][n].sel==SELECTED1) xctx->rect[c][n].sel = SELECTED2;
|
|
else if(xctx->rect[c][n].sel==SELECTED2) xctx->rect[c][n].sel = SELECTED1;
|
|
else if(xctx->rect[c][n].sel==SELECTED3) xctx->rect[c][n].sel = SELECTED4;
|
|
else if(xctx->rect[c][n].sel==SELECTED4) xctx->rect[c][n].sel = SELECTED3;
|
|
}
|
|
if( xctx->ry2 == ty1) {
|
|
if(xctx->rect[c][n].sel==SELECTED1) xctx->rect[c][n].sel = SELECTED3;
|
|
else if(xctx->rect[c][n].sel==SELECTED3) xctx->rect[c][n].sel = SELECTED1;
|
|
else if(xctx->rect[c][n].sel==SELECTED2) xctx->rect[c][n].sel = SELECTED4;
|
|
else if(xctx->rect[c][n].sel==SELECTED4) xctx->rect[c][n].sel = SELECTED2;
|
|
}
|
|
|
|
xctx->rect[c][n].x1 = xctx->rx1;
|
|
xctx->rect[c][n].y1 = xctx->ry1;
|
|
xctx->rect[c][n].x2 = xctx->rx2;
|
|
xctx->rect[c][n].y2 = xctx->ry2;
|
|
|
|
/* bbox after move */
|
|
break;
|
|
|
|
case xTEXT:
|
|
if(k!=TEXTLAYER) break;
|
|
#if HAS_CAIRO==1 /* bbox before move */
|
|
customfont = set_text_custom_font(&xctx->text[n]);
|
|
#endif
|
|
text_bbox(get_text_floater(n), xctx->text[n].xscale,
|
|
xctx->text[n].yscale, xctx->text[n].rot,xctx->text[n].flip, xctx->text[n].hcenter,
|
|
xctx->text[n].vcenter, xctx->text[n].x0, xctx->text[n].y0,
|
|
&xctx->rx1,&xctx->ry1, &xctx->rx2,&xctx->ry2, &tmpint, &dtmp);
|
|
#if HAS_CAIRO==1
|
|
if(customfont) {
|
|
cairo_restore(xctx->cairo_ctx);
|
|
}
|
|
#endif
|
|
if(xctx->rotatelocal) {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->text[n].x0, xctx->text[n].y0,
|
|
xctx->text[n].x0, xctx->text[n].y0, xctx->rx1,xctx->ry1);
|
|
} else {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
xctx->text[n].x0, xctx->text[n].y0, xctx->rx1,xctx->ry1);
|
|
}
|
|
xctx->text[n].x0=xctx->rx1+xctx->deltax;
|
|
xctx->text[n].y0=xctx->ry1+xctx->deltay;
|
|
xctx->text[n].rot=(xctx->text[n].rot +
|
|
( (xctx->move_flip && (xctx->text[n].rot & 1) ) ? xctx->move_rot+2 : xctx->move_rot) ) & 0x3;
|
|
xctx->text[n].flip=xctx->move_flip^xctx->text[n].flip;
|
|
|
|
#if HAS_CAIRO==1 /* bbox after move */
|
|
customfont = set_text_custom_font(&xctx->text[n]);
|
|
#endif
|
|
text_bbox(get_text_floater(n), xctx->text[n].xscale,
|
|
xctx->text[n].yscale, xctx->text[n].rot,xctx->text[n].flip, xctx->text[n].hcenter,
|
|
xctx->text[n].vcenter, xctx->text[n].x0, xctx->text[n].y0,
|
|
&xctx->rx1,&xctx->ry1, &xctx->rx2,&xctx->ry2, &tmpint, &dtmp);
|
|
#if HAS_CAIRO==1
|
|
if(customfont) {
|
|
cairo_restore(xctx->cairo_ctx);
|
|
}
|
|
#endif
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
} /* end switch(xctx->sel_array[i].type) */
|
|
} /* end for(i=0;i<xctx->lastsel; ++i) */
|
|
} /*end for(k=0;k<cadlayers; ++k) */
|
|
|
|
for(i = 0; i < xctx->lastsel; ++i) {
|
|
n = xctx->sel_array[i].n;
|
|
if(xctx->sel_array[i].type == ELEMENT) {
|
|
xctx->prep_hash_inst=0;
|
|
firsti = 0;
|
|
if(xctx->rotatelocal) {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->inst[n].x0, xctx->inst[n].y0,
|
|
xctx->inst[n].x0, xctx->inst[n].y0, xctx->rx1,xctx->ry1);
|
|
} else {
|
|
ROTATION(xctx->move_rot, xctx->move_flip, xctx->x1, xctx->y_1,
|
|
xctx->inst[n].x0, xctx->inst[n].y0, xctx->rx1,xctx->ry1);
|
|
}
|
|
xctx->inst[n].x0 = xctx->rx1+xctx->deltax;
|
|
xctx->inst[n].y0 = xctx->ry1+xctx->deltay;
|
|
xctx->inst[n].rot = (xctx->inst[n].rot +
|
|
( (xctx->move_flip && (xctx->inst[n].rot & 1) ) ? xctx->move_rot+2 : xctx->move_rot) ) & 0x3;
|
|
xctx->inst[n].flip = xctx->move_flip ^ xctx->inst[n].flip;
|
|
symbol_bbox(n,
|
|
&xctx->inst[n].x1, &xctx->inst[n].y1,
|
|
&xctx->inst[n].x2, &xctx->inst[n].y2);
|
|
}
|
|
}
|
|
if(!firsti || !firstw) {
|
|
xctx->prep_net_structs=0;
|
|
xctx->prep_hi_structs=0;
|
|
}
|
|
/* build after copying and after recalculating prepare_netlist_structs() */
|
|
check_collapsing_objects();
|
|
unselect_partial_sel_wires();
|
|
if(tclgetboolvar("autotrim_wires")) trim_wires();
|
|
|
|
if(xctx->hilight_nets) {
|
|
propagate_hilights(1, 1, XINSERT_NOREPLACE);
|
|
}
|
|
|
|
xctx->ui_state &= ~STARTMOVE;
|
|
if(xctx->ui_state & STARTMERGE) xctx->ui_state |= SELECTION; /* leave selection state so objects can be deleted */
|
|
xctx->ui_state &= ~STARTMERGE;
|
|
xctx->move_rot=xctx->move_flip=0;
|
|
xctx->x1=xctx->y_1=xctx->x2=xctx->y_2=xctx->deltax=xctx->deltay=0.;
|
|
set_modify(1); /* must be done before draw() if floaters are present to force cached values update */
|
|
draw();
|
|
xctx->rotatelocal=0;
|
|
} /* what & end */
|
|
draw_selection(xctx->gc[SELLAYER], 0);
|
|
if(tclgetboolvar("draw_crosshair")) draw_crosshair(0);
|
|
}
|