Extended the "paint" and "erase" commands to accept an option
"pick x y" which acts like "cursor", but operates on a database coordinate instead of a pointer coordinate. Made a few other corrections to the command logging code so that it produces valid output when the log file is sourced.
This commit is contained in:
parent
3890181ebe
commit
7a4a867d6e
|
|
@ -797,6 +797,13 @@ CmdBox(w, cmd)
|
|||
ToolMoveCorner(tcorner, &cmd->tx_p, TRUE, rootBoxDef);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Recast command as "box values" for logging purposes */
|
||||
ToolGetBox(&rootBoxDef, &rootBox);
|
||||
sprintf(cmd->tx_argstring, "box values %di %di %di %di",
|
||||
rootBox.r_xbot, rootBox.r_ybot,
|
||||
rootBox.r_xtop, rootBox.r_ytop);
|
||||
TxRebuildCommand(cmd);
|
||||
return;
|
||||
}
|
||||
else if (DBWSnapToGrid != DBW_SNAP_USER)
|
||||
|
|
|
|||
|
|
@ -2711,6 +2711,14 @@ CmdCopy(w, cmd)
|
|||
return;
|
||||
}
|
||||
|
||||
/* Recast the command as "copy to x y" so that it no longer
|
||||
* depends on the pointer position, for command logging.
|
||||
*/
|
||||
GeoTransPoint(&RootToEditTransform, &rootPoint, &editPoint);
|
||||
sprintf(cmd->tx_argstring, "copy to %di %di\n", editPoint.p_x,
|
||||
editPoint.p_y);
|
||||
TxRebuildCommand(cmd);
|
||||
|
||||
copyToPoint:
|
||||
if (!ToolGetBox(&rootDef, &rootBox) || (rootDef != SelectRootDef))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -598,7 +598,7 @@ badusage:
|
|||
* EditCellUse->cu_def.
|
||||
*
|
||||
* Usage:
|
||||
* erase [layers | cursor]
|
||||
* erase [layers | cursor | pick x y]
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
|
|
@ -630,14 +630,23 @@ CmdErase(w, cmd)
|
|||
windCheckOnlyWindow(&w, DBWclientID);
|
||||
if (w == (MagWindow *) NULL) return;
|
||||
|
||||
if ((cmd->tx_argc == 4) && !strcmp(cmd->tx_argv[1], "pick"))
|
||||
{
|
||||
Point editPoint, rootPoint;
|
||||
editPoint.p_x = cmdParseCoord(w, cmd->tx_argv[2], FALSE, TRUE);
|
||||
editPoint.p_y = cmdParseCoord(w, cmd->tx_argv[3], FALSE, FALSE);
|
||||
GeoTransPoint(&EditToRootTransform, &editPoint, &rootPoint);
|
||||
CmdPaintEraseButton(w, &rootPoint, FALSE, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd->tx_argc > 2)
|
||||
{
|
||||
TxError("Usage: %s [<layers> | cursor]\n", cmd->tx_argv[0]);
|
||||
TxError("Usage: %s [<layers> | cursor | pick x y]\n", cmd->tx_argv[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ToolGetEditBox(&editRect)) return;
|
||||
|
||||
if (EditCellUse == NULL)
|
||||
{
|
||||
TxError("No cell def being edited!\n");
|
||||
|
|
@ -654,7 +663,16 @@ CmdErase(w, cmd)
|
|||
(void) CmdParseLayers("*,label", &mask);
|
||||
else if (!strncmp(cmd->tx_argv[1], "cursor", 6))
|
||||
{
|
||||
CmdPaintEraseButton(w, &cmd->tx_p, FALSE);
|
||||
Point editPoint, rootPoint;
|
||||
|
||||
CmdPaintEraseButton(w, &cmd->tx_p, FALSE, TRUE);
|
||||
|
||||
/* Recast the command as "erase pick x y" for logging purposes */
|
||||
CmdGetRootPoint(&rootPoint, (Rect *)NULL);
|
||||
GeoTransPoint(&RootToEditTransform, &rootPoint, &editPoint);
|
||||
sprintf(cmd->tx_argstring, "erase pick %di %di", editPoint.p_x,
|
||||
editPoint.p_y);
|
||||
TxRebuildCommand(cmd);
|
||||
return;
|
||||
}
|
||||
else if (!CmdParseLayers(cmd->tx_argv[1], &mask))
|
||||
|
|
|
|||
|
|
@ -815,6 +815,14 @@ CmdMove(w, cmd)
|
|||
return;
|
||||
}
|
||||
|
||||
/* Recast the command as "move to x y" so that it no longer
|
||||
* depends on the pointer position, for command logging.
|
||||
*/
|
||||
GeoTransPoint(&RootToEditTransform, &rootPoint, &editPoint);
|
||||
sprintf(cmd->tx_argstring, "move to %di %di\n", editPoint.p_x,
|
||||
editPoint.p_y);
|
||||
TxRebuildCommand(cmd);
|
||||
|
||||
moveToPoint:
|
||||
if (!ToolGetBox(&rootDef, &rootBox) || (rootDef != SelectRootDef))
|
||||
{
|
||||
|
|
@ -871,7 +879,7 @@ moveToPoint:
|
|||
* Paint the specified layers underneath the box in EditCellUse->cu_def.
|
||||
*
|
||||
* Usage:
|
||||
* paint <layers> | cursor
|
||||
* paint <layers> | cursor | pick x y
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
|
|
@ -897,15 +905,34 @@ CmdPaint(w, cmd)
|
|||
return;
|
||||
}
|
||||
|
||||
if ((cmd->tx_argc == 4) && !strcmp(cmd->tx_argv[1], "pick"))
|
||||
{
|
||||
Point editPoint, rootPoint;
|
||||
editPoint.p_x = cmdParseCoord(w, cmd->tx_argv[2], FALSE, TRUE);
|
||||
editPoint.p_y = cmdParseCoord(w, cmd->tx_argv[3], FALSE, FALSE);
|
||||
GeoTransPoint(&EditToRootTransform, &editPoint, &rootPoint);
|
||||
CmdPaintEraseButton(w, &rootPoint, TRUE, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd->tx_argc != 2)
|
||||
{
|
||||
TxError("Usage: %s <layers> | cursor\n", cmd->tx_argv[0]);
|
||||
TxError("Usage: %s <layers> | cursor | pick x y\n", cmd->tx_argv[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strncmp(cmd->tx_argv[1], "cursor", 6))
|
||||
{
|
||||
CmdPaintEraseButton(w, &cmd->tx_p, TRUE);
|
||||
Point editPoint, rootPoint;
|
||||
|
||||
CmdPaintEraseButton(w, &cmd->tx_p, TRUE, TRUE);
|
||||
|
||||
/* Recast the command as "paint pick x y" for logging purposes */
|
||||
CmdGetRootPoint(&rootPoint, (Rect *)NULL);
|
||||
GeoTransPoint(&RootToEditTransform, &rootPoint, &editPoint);
|
||||
sprintf(cmd->tx_argstring, "paint pick %di %di", editPoint.p_x,
|
||||
editPoint.p_y);
|
||||
TxRebuildCommand(cmd);
|
||||
return;
|
||||
}
|
||||
else if (!CmdParseLayers(cmd->tx_argv[1], &mask))
|
||||
|
|
@ -957,10 +984,11 @@ CmdPaint(w, cmd)
|
|||
*/
|
||||
|
||||
void
|
||||
CmdPaintEraseButton(w, butPoint, isPaint)
|
||||
CmdPaintEraseButton(w, refPoint, isPaint, isScreen)
|
||||
MagWindow *w;
|
||||
Point *butPoint; /* Screen location at which button was raised */
|
||||
Point *refPoint; /* Screen location at which button was raised */
|
||||
bool isPaint; /* True for paint, False for erase. */
|
||||
bool isScreen; /* True for screen coordinates, False for root */
|
||||
{
|
||||
Rect rootRect, editRect, areaReturn;
|
||||
TileTypeBitMask mask;
|
||||
|
|
@ -974,7 +1002,15 @@ CmdPaintEraseButton(w, butPoint, isPaint)
|
|||
}
|
||||
crec = (DBWclientRec *) w->w_clientData;
|
||||
|
||||
WindPointToSurface(w, butPoint, (Point *) NULL, &rootRect);
|
||||
if (isScreen)
|
||||
WindPointToSurface(w, refPoint, (Point *) NULL, &rootRect);
|
||||
else
|
||||
{
|
||||
rootRect.r_ll.p_x = refPoint->p_x;
|
||||
rootRect.r_ll.p_y = refPoint->p_y;
|
||||
rootRect.r_ur.p_x = refPoint->p_x + 1;
|
||||
rootRect.r_ur.p_y = refPoint->p_y + 1;
|
||||
}
|
||||
|
||||
DBSeeTypesAll(((CellUse *)w->w_surfaceID), &rootRect,
|
||||
crec->dbw_bitmask, &mask);
|
||||
|
|
|
|||
|
|
@ -1311,7 +1311,21 @@ Okay:
|
|||
}
|
||||
else
|
||||
{
|
||||
char *aptr;
|
||||
int i;
|
||||
|
||||
window = CmdGetRootPoint((Point *) NULL, &scx.scx_area);
|
||||
|
||||
/* Recast command with "at x y" at the end for logging */
|
||||
for (i = 0; i < cmd->tx_argc; i++)
|
||||
{
|
||||
aptr = cmd->tx_argv[i] + strlen(cmd->tx_argv[i]);
|
||||
*aptr = ' ';
|
||||
}
|
||||
sprintf(aptr + 1, "at %di %di", scx.scx_area.r_xbot,
|
||||
scx.scx_area.r_ybot);
|
||||
TxRebuildCommand(cmd);
|
||||
|
||||
}
|
||||
if (window == NULL) return;
|
||||
scx.scx_use = (CellUse *) window->w_surfaceID;
|
||||
|
|
|
|||
|
|
@ -351,7 +351,7 @@ DBWBoxHandler(w, cmd)
|
|||
if (button == TX_MIDDLE_BUTTON)
|
||||
{
|
||||
if (cmd->tx_buttonAction == TX_BUTTON_DOWN)
|
||||
CmdPaintEraseButton(w, &cmd->tx_p, TRUE);
|
||||
CmdPaintEraseButton(w, &cmd->tx_p, TRUE, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,11 +39,12 @@ Erase paint from the layout inside the bounds of the cursor box.
|
|||
|
||||
<H3>Usage:</H3>
|
||||
<BLOCKQUOTE>
|
||||
<B>erase</B> [<I>layers</I>|<B>cursor</B>] <BR><BR>
|
||||
<B>erase</B> [<I>layers</I>|<B>cursor</B>|<B>pick</B> <I>x y</I>] <BR><BR>
|
||||
<BLOCKQUOTE>
|
||||
where <I>layers</I> is a comma-separated list of layer types
|
||||
to be erased, or <B>*</B> to indicate all paint but not labels,
|
||||
or <B>$</B> to indicate both paint and labels.
|
||||
or <B>$</B> to indicate both paint and labels; and where <I>x</I>
|
||||
and <I>y</I> are values in the layout coordinate system.
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
|
|
@ -62,6 +63,11 @@ Erase paint from the layout inside the bounds of the cursor box.
|
|||
of the (X11) cursor and erases these from the area of the cursor
|
||||
box. <P>
|
||||
|
||||
The option "<B>erase pick</B> <I>x y</I>" works like "<B>erase
|
||||
cursor</B>", but the type of material to erase is selected from
|
||||
the given position in layout coordinates instead of a pointer
|
||||
position. <P>
|
||||
|
||||
Note that when applied to contact types, "<B>erase</B>" will erase
|
||||
the entire contact, including the top and bottom metal types
|
||||
comprising the contact. To remove the contact cuts without affecting
|
||||
|
|
|
|||
|
|
@ -33,9 +33,10 @@ Paint mask information into the current edit cell
|
|||
|
||||
<H3>Usage:</H3>
|
||||
<BLOCKQUOTE>
|
||||
<B>paint</B> <I>layers</I>|<B>cursor</B> <BR><BR>
|
||||
<B>paint</B> <I>layers</I>|<B>cursor</B>|<B>pick</B> <I>x y</I> <BR><BR>
|
||||
<BLOCKQUOTE>
|
||||
where <I>layers</I> is a comma-separated list of types to paint.
|
||||
where <I>layers</I> is a comma-separated list of types to paint,
|
||||
and <I>x y</I> are coordinates in the layout coordinate system.
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
|
|
@ -52,7 +53,11 @@ Paint mask information into the current edit cell
|
|||
position of the (X11) cursor and fills the cursor box with these
|
||||
types. However, when no material (e.g., "space") is present under
|
||||
the cursor, then all material and labels are erased from the
|
||||
area of the cursor box.
|
||||
area of the cursor box. <P>
|
||||
|
||||
The "<B>paint pick</B> <I>x y</I>" option works like "<B>paint
|
||||
cursor</B>", but the type of paint is selected from the given
|
||||
position in layout coordinates instead of a pointer position.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3>Implementation Notes:</H3>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ proc magic::suspendall {} {
|
|||
set framename $window
|
||||
}
|
||||
if {[incr Winopts(${framename},suspend)] == 1} {
|
||||
$window update suspend
|
||||
$window updatedisplay suspend
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -42,7 +42,7 @@ proc magic::resumeall {} {
|
|||
incr Winopts($framename,suspend) -1
|
||||
if { $Winopts(${framename},suspend) <= 0 } {
|
||||
unset Winopts(${framename},suspend)
|
||||
$window update resume
|
||||
$window updatedisplay resume
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -856,31 +856,16 @@ txLogCommand(cmd)
|
|||
return;
|
||||
else if (!strcmp(postns, "*bypass"))
|
||||
return;
|
||||
|
||||
/* Commands ending in "cursor" should be preceeded by a set point */
|
||||
/* to indicate where the pointer was at the time of the command. */
|
||||
|
||||
if (!strcmp(cmd->tx_argv[cmd->tx_argc - 1], "cursor"))
|
||||
{
|
||||
if (cmd->tx_wid >= 0)
|
||||
{
|
||||
/* Command has a window associated with it. */
|
||||
fprintf(txLogFile, "%ssetpoint %d %d %d\n",
|
||||
pfix, cmd->tx_p.p_x, cmd->tx_p.p_y, cmd->tx_wid);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No window associated with the command. */
|
||||
fprintf(txLogFile, "%ssetpoint %d %d\n",
|
||||
pfix, cmd->tx_p.p_x, cmd->tx_p.p_y);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(postns, "setpoint")) return;
|
||||
|
||||
fprintf(txLogFile, "%s%s", pfix, cmd->tx_argv[0]);
|
||||
for (i = 1; i < cmd->tx_argc; i++)
|
||||
{
|
||||
fprintf(txLogFile, " %s", cmd->tx_argv[i]);
|
||||
bool needQuotes = (strchr(cmd->tx_argv[i], ' ') == NULL) ? FALSE : TRUE;
|
||||
fprintf(txLogFile, " ");
|
||||
if (needQuotes) fprintf(txLogFile, "\"");
|
||||
fprintf(txLogFile, "%s", cmd->tx_argv[i]);
|
||||
if (needQuotes) fprintf(txLogFile, "\"");
|
||||
}
|
||||
fprintf(txLogFile, "\n");
|
||||
}
|
||||
|
|
@ -1300,6 +1285,45 @@ txGetFileCommand(f, queue)
|
|||
TxParseString(linep, queue, (TxInputEvent *) NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* TxRebuildCommand:
|
||||
*
|
||||
* Rebuild the arguments of a TxCommand structure. This assumes
|
||||
* that a routine has rewritten the tx_argstring record with a
|
||||
* modified command. Tokenize the tx_argstring and update the
|
||||
* tx_argc count and tx_argv pointers.
|
||||
*
|
||||
* The purpose of this routine is to allow some command callbacks
|
||||
* to change the command from one implying the use of pointer
|
||||
* coordinates to an equivalent command that uses database units,
|
||||
* for the purpose of logging the command.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
TxRebuildCommand(TxCommand *cmd)
|
||||
{
|
||||
char *cptr, *tptr, c;
|
||||
|
||||
cmd->tx_argc = 0;
|
||||
tptr = cptr = cmd->tx_argstring;
|
||||
|
||||
do
|
||||
{
|
||||
c = *cptr;
|
||||
if ((c == ' ') || (c == '\0'))
|
||||
{
|
||||
cmd->tx_argv[cmd->tx_argc] = tptr;
|
||||
cmd->tx_argc++;
|
||||
*cptr = '\0';
|
||||
tptr = cptr + 1;
|
||||
}
|
||||
cptr++;
|
||||
}
|
||||
while (c != '\0');
|
||||
}
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -158,6 +158,7 @@ extern TxCommand *TxNewCommand();
|
|||
extern void TxFreeCommand();
|
||||
extern void TxParseString();
|
||||
extern void TxDispatch();
|
||||
extern void TxRebuildCommand();
|
||||
extern int TxCommandNumber; /* Serial number of current command. */
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
|
|
|
|||
Loading…
Reference in New Issue