magic/netmenu/NMlabel.c

655 lines
17 KiB
C
Raw Normal View History

/* NMlabel.c -
*
* This file contains routines that handle the label portion
* of net-list menus. The routines do things like reading
* labels from the terminal, placing labels in the design,
* re-orienting label text, and incrementing numbers inside
* of labels.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/netmenu/NMlabel.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "utils/utils.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "windows/windows.h"
#include "utils/main.h"
#include "dbwind/dbwind.h"
#include "netmenu/nmInt.h"
#include "textio/textio.h"
#include "textio/txcommands.h"
#include "commands/commands.h"
#include "utils/styles.h"
#include "utils/malloc.h"
/* The user can enter several labels at once, so he doesn't have
* to keep going back and forth between the mouse and the keyboard.
* We store the labels in a big array. At any given time, only one
* of them is visible in the menu; only it can be placed in the
* design. There are menu buttons for going to the next or previous
* label.
*/
#define MAXLABELS 100
char * nmLabelArray[MAXLABELS]; /* Holds pointers to all labels
* entered together.
*/
int nmCurLabel; /* Index of current label. */
int nmNum1 = -1; /* First two numbers in current label. */
int nmNum2 = -1;
char nmNum1String[12]; /* String equivalents of nmNum1 and nmNum2. */
char nmNum2String[12];
/*
* ----------------------------------------------------------------------------
*
* nmGetNums --
*
* Picks one or two positive decimal numbers out of a string of text.
*
* Results:
* None.
*
* Side effects:
* The string is scanned for positive decimal numbers. If any are
* found, the first one is put in num1 and the second one is put in
* num2. If there aren't two numbers, num1 and/or num2 will be
* set to -1. This routine ignores "-" signs, so the numbers are
* always positive.
*
* ----------------------------------------------------------------------------
*/
void
nmGetNums(string, num1, num2)
char *string; /* String to scan. */
int *num1, *num2; /* Pointers to places to store numbers. */
{
char *p;
bool gotNum = FALSE;
bool gotDigit = FALSE;
int num = 0;
*num1 = *num2 = -1;
for (p = string; ; p++)
{
if (isdigit(*p))
{
num = (10*num) + *p - '0';
gotDigit = TRUE;
}
else if (gotDigit)
{
if (gotNum)
{
*num2 = num;
return;
}
*num1 = num;
gotDigit = FALSE;
gotNum = TRUE;
num = 0;
}
if (*p == 0) return;
}
}
/*
* ----------------------------------------------------------------------------
*
* nmPutNums --
*
* This routine generates a new string by replaces the first two
* numbers in an old string with new numbers.
*
* Results:
* The return value is a pointer to a string that is identical
* to src, except that if there are decimal numbers in src, the
* first two of those are replaced with the string equivalents
* of num1 and num2. For example, if src is "bus[14,22]" and
* num1 is 3 and num2 is 177, the return value will be "bus[3,177]".
* Note: the result is a statically allocated string, so the
* caller should copy it before calling this routine again.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
char *
nmPutNums(src, num1, num2)
char *src; /* String on which substitution is
* to be done. */
int num1, num2; /* Numbers to substitute. A number less
* than zero means keep the old value.
*/
{
static char *result = NULL;
static int resultLength = 0;
char num1String[12], num2String[12];
int spaceNeeded;
char *pSrc, *pResult;
/* First, translate the numbers into strings. Then, make sure
* we have enough space to store the result. Allocate a new
* result area if there isn't enough space. The space computation
* is a bit conservative, but simpler that way.
*/
(void) sprintf(num1String, "%d", num1);
(void) sprintf(num2String, "%d", num2);
spaceNeeded = strlen(num1String) + strlen(num2String) + strlen(src) + 1;
if (resultLength < spaceNeeded)
{
if (result != NULL) freeMagic(result);
result = mallocMagic((unsigned) spaceNeeded);
resultLength = spaceNeeded;
}
/* Now scan through the source string. Copy everything up
* to the first number into the result.
*/
pSrc = src;
pResult = result;
while (!isdigit(*pSrc))
if ((*pResult++ = *pSrc++) == 0) return result;
/* Now copy num1String into result and skip the number in
* the original string. Or, if num1 is less than zero,
* then just copy the number from src.
*/
if (num1 < 0)
{
while (isdigit(*pSrc)) *pResult++ = *pSrc++;
}
else
{
while (isdigit(*pSrc)) pSrc += 1;
(void) strcpy(pResult, num1String);
while (isdigit(*pResult)) pResult += 1;
}
/* Copy more non-digits from source to destination. */
while (!isdigit(*pSrc))
if ((*pResult++ = *pSrc++) == 0) return result;
/* Copy the second number. */
if (num2 < 0)
{
while (isdigit(*pSrc)) *pResult++ = *pSrc++;
}
else
{
while (isdigit(*pSrc)) pSrc += 1;
(void) strcpy(pResult, num2String);
while (isdigit(*pResult)) pResult += 1;
}
/* Copy the rest of the source to the destination. */
while (TRUE)
if ((*pResult++ = *pSrc++) == 0) return result;
}
/*
* ----------------------------------------------------------------------------
*
* nmSetCurrentLabel --
*
* This is a utility procedure called when the current label changes.
*
* Results:
* None.
*
* Side effects:
* Number information is extracted from the label, and the menu
* is redisplayed.
*
* ----------------------------------------------------------------------------
*/
void
nmSetCurrentLabel()
{
nmGetNums(nmLabelArray[nmCurLabel], &nmNum1, &nmNum2);
if (nmNum1 >= 0) (void) sprintf(nmNum1String, "%d", nmNum1);
else nmNum1String[0] = 0;
if (nmNum2 >= 0) (void) sprintf(nmNum2String, "%d", nmNum2);
else nmNum2String[0] = 0;
/* Set up the menu buttons to refer to this information, and
* redisplay relevant stuff.
*/
NMLabelButton.nmb_text = nmLabelArray[nmCurLabel];
NMNum1Button.nmb_text = nmNum1String;
NMNum2Button.nmb_text = nmNum2String;
if (NMWindow != NULL)
{
(void) NMredisplay(NMWindow, &NMLabelButton.nmb_area, (Rect *) NULL);
(void) NMredisplay(NMWindow, &NMNum1Button.nmb_area, (Rect *) NULL);
(void) NMredisplay(NMWindow, &NMNum2Button.nmb_area, (Rect *) NULL);
}
}
/*
* ----------------------------------------------------------------------------
*
* NMGetLabels --
*
* Reads in a bunch of labels from the terminal, and makes the
* first of them "current".
*
* Results:
* None.
*
* Side effects:
* The old group of labels is re-allocated, and replaced by a new
* group read from the terminal. The first of the new group is
* made the current label in the net-list menu.
*
* ----------------------------------------------------------------------------
*/
void
NMGetLabels()
{
#define MAXLENGTH 200
char line[MAXLENGTH]; /* Holds label temporarily. */
int i;
TxPrintf("Enter labels, one per line, terminated by a blank line:\n");
for (i = 0; i < MAXLABELS; i++)
{
if (TxGetLine(line, MAXLENGTH) == NULL) line[0] = 0;
if (line[0] == 0)
{
/* All done. If we got any labels at all, null out all
* the remaining old labels.
*/
if (i == 0)
{
TxPrintf("No new labels given, so I'll keep the old ones.\n");
return;
}
for ( ; i < MAXLABELS; i++)
(void) StrDup(&(nmLabelArray[i]), (char *) NULL);
break;
}
(void) StrDup(&(nmLabelArray[i]), line);
}
/* Make the first label current, and extract its two numbers. */
nmCurLabel = 0;
nmSetCurrentLabel();
}
/*
* ----------------------------------------------------------------------------
*
* NMNextLabel and NMPrevLabel --
*
* These procedures are invoked in response to button pushes
* over the label button. They make the next or previous label
* in the list to be the current one.
*
* Results:
* None.
*
* Side effects:
* The current label is changed.
*
* ----------------------------------------------------------------------------
*/
void
NMNextLabel()
{
if (nmLabelArray[nmCurLabel] == NULL)
{
TxError("Use the left button to enter labels first.\n");
return;
}
if ((nmCurLabel == MAXLABELS-1) || (nmLabelArray[nmCurLabel+1] == NULL))
nmCurLabel = 0;
else nmCurLabel += 1;
nmSetCurrentLabel();
}
void
NMPrevLabel()
{
if (nmLabelArray[nmCurLabel] == NULL)
{
TxError("Use the left button to enter labels first.\n");
return;
}
if (nmCurLabel == 0)
{
for (nmCurLabel = MAXLABELS-1; nmLabelArray[nmCurLabel] == NULL;
nmCurLabel -= 1) /* null loop body */;
}
else nmCurLabel -= 1;
nmSetCurrentLabel();
}
/*
* ----------------------------------------------------------------------------
*
* NMChangeNum --
*
* This procedure increments or decrements one of the two numbers
* we've extracted from the current label. It is called in response
* to a button push inside one of the number buttons.
*
* Results:
* None.
*
* Side effects:
* One of the numbers is incremented or decremented, and the label
* information gets redisplayed.
*
* ----------------------------------------------------------------------------
*/
/* ARGSUSED */
void
NMChangeNum(window,cmd, nmButton, point)
MagWindow *window; /* Window in which button was pushed. */
NetButton *nmButton; /* NetButton where button was pushed. */
TxCommand *cmd; /* Exact command invoked. */
Point *point; /* Cursor position in surface coords. */
{
int *pNum;
/* Figure out which number is involved. */
if (nmButton == &NMNum1Button) pNum = &nmNum1;
else pNum = &nmNum2;
/* Increment or decrement the number. */
if (*pNum < 0)
{
TxError("That number doesn't exist!\n");
return;
}
if (cmd->tx_button != TX_LEFT_BUTTON) *pNum += 1;
else
{
if (*pNum == 0)
{
TxError("Can't decrement past zero.\n");
return;
}
*pNum -= 1;
}
/* Fill in the new numbers in the string, and update the screen. */
(void) StrDup(&(nmLabelArray[nmCurLabel]),
nmPutNums(nmLabelArray[nmCurLabel], nmNum1, nmNum2));
nmSetCurrentLabel();
}
/*
* ----------------------------------------------------------------------------
*
* nmGetPos --
*
* This is a utility procedure to determine which label position
* was selected on a button push.
*
* Results:
* The return value is a label position. This is determined by
* dividing the button area into 9 sectors and using the sector
* number to select a label position. The position is transformed
* into edit cell coordinates before returning.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
int
nmGetPos(button, point)
NetButton *button; /* Button where the mouse was clicked. */
Point *point; /* Exact surface position within the button. */
{
/* The following table maps from sectors to label positions. */
static int pos[] =
{
GEO_SOUTHWEST, GEO_SOUTH, GEO_SOUTHEAST,
GEO_WEST, GEO_CENTER, GEO_EAST,
GEO_NORTHWEST, GEO_NORTH, GEO_NORTHEAST
};
int x, y, tmp;
/* Divide the button area into thirds in x and y, and figure out
* which sector contains the point.
*/
tmp = (button->nmb_area.r_xtop - button->nmb_area.r_xbot + 1)/3;
if (point->p_x <= button->nmb_area.r_xbot + tmp) x = 0;
else if (point->p_x >= button->nmb_area.r_xtop - tmp) x = 2;
else x = 1;
tmp = (button->nmb_area.r_ytop - button->nmb_area.r_ybot + 1)/3;
if (point->p_y <= button->nmb_area.r_ybot + tmp) y = 0;
else if (point->p_y >= button->nmb_area.r_ytop - tmp) y = 2;
else y = 1;
return GeoTransPos(&RootToEditTransform, pos[3*y + x]);
}
/*
* ----------------------------------------------------------------------------
*
* NMPutLabel --
*
* This procedure is invoked when the left button is pushed over
* the button for placing labels. It places the current label
* in the design at the position of the box, and with an orientation
* determined by the place where the button was pushed.
*
* Results:
* None.
*
* Side effects:
* A label is added to the edit cell.
*
* ----------------------------------------------------------------------------
*/
/* ARGSUSED */
void
NMPutLabel(window, cmd, nmButton, point)
MagWindow *window; /* Window where mouse button was pushed.
* (ignored) */
NetButton *nmButton; /* Menu button activated. */
TxCommand *cmd; /* Complete info about command. (ignored) */
Point *point; /* Cursor position in surface coords. */
{
int pos;
char *text;
text = nmLabelArray[nmCurLabel];
if ((text == NULL) || (*text == 0))
{
TxError("Enter some text first (left-button the label entry).\n");
return;
}
pos = nmGetPos(nmButton, point);
CmdLabelProc(text, -1, 1, 0, 0, 0, pos, 0, (TileType)-1);
}
/*
* ----------------------------------------------------------------------------
*
* NMReOrientLabel --
*
* This procedure is invoked by button pushes inside the net-list
* menu. It resets the text positions of all labels touching the
* box.
*
* Results:
* None.
*
* Side effects:
* Label positions are changed.
*
* ----------------------------------------------------------------------------
*/
/* ARGSUSED */
void
NMReOrientLabel(window, cmd, nmButton, point)
MagWindow *window; /* Window that was buttoned. (ignored) */
NetButton *nmButton; /* Button that was clicked. */
TxCommand *cmd; /* Detailed info on command (ignored). */
Point *point; /* Cursor position in surface coords. */
{
int pos;
Rect editArea;
/* Make sure that the box exists. */
if (!ToolGetEditBox(&editArea)) return;
pos = nmGetPos(nmButton, point);
DBReOrientLabel(EditCellUse->cu_def, &editArea, pos);
}
/*
* ----------------------------------------------------------------------------
*
* NMFindLabel --
*
* Use the current label as a search pattern and create feedback
* areas for all instances of labels with that pattern.
*
* Results:
* None.
*
* Side effects:
* New feedback areas get created.
*
* ----------------------------------------------------------------------------
*/
void
NMFindLabel()
{
char *pattern;
pattern = nmLabelArray[nmCurLabel];
if ((pattern == NULL) || (*pattern == 0))
{
TxError("Enter some text first (left-button the label entry).\n");
return;
}
NMShowLabel(pattern, (TileTypeBitMask *) NULL);
}
/*
* ----------------------------------------------------------------------------
*
* NMShowLabel --
*
* This procedure creates feedback for each instance of a label
* matching pattern that lies underneath the box. This procedure
* looks at all cells in the hierarchy, expanded or not.
*
* Results:
* None.
*
* Side effects:
* Feedback areas are created and displayed.
*
* ----------------------------------------------------------------------------
*/
void
NMShowLabel(pattern, pMask)
char *pattern; /* Pattern to be searched for. */
TileTypeBitMask *pMask;
{
SearchContext scx;
MagWindow *w;
int nmlLabelFunc();
w = ToolGetBoxWindow(&scx.scx_area, (int *) NULL);
if (w == NULL)
{
TxError("There's no box! Please use the box to select\n");
TxError("the area to search for a label match.\n");
return;
}
scx.scx_use = (CellUse *) w->w_surfaceID;
scx.scx_trans = GeoIdentityTransform;
if (pMask == NULL)
pMask = &DBAllTypeBits;
(void) DBSearchLabel(&scx, pMask, 0, pattern,
nmlLabelFunc, (ClientData) scx.scx_use->cu_def);
}
/* ARGSUSED */
int
nmlLabelFunc(scx, label, tpath, rootDef)
SearchContext *scx; /* Describes state of search. */
Label *label; /* Pointer to label found. */
TerminalPath *tpath; /* Not used. */
CellDef *rootDef; /* Root def for search. */
{
char mesg[2048];
Rect rootArea;
int left;
/* Finish generating the full hierarchical name */
left = tpath->tp_last - tpath->tp_next - 1;
(void) strncpy(tpath->tp_next, label->lab_text, left);
tpath->tp_next[left] = '\0';
(void) sprintf(mesg, "%s;%s",
DBTypeShortName(label->lab_type), tpath->tp_first);
GeoTransRect(&scx->scx_trans, &label->lab_rect, &rootArea);
GEO_EXPAND(&rootArea, 1, &rootArea);
DBWFeedbackAdd(&rootArea, mesg, rootDef, 1,
STYLE_PALEHIGHLIGHTS);
return 0;
}