Files
magic/netmenu/NMlabel.c
T
Patrick Kurth ea03883829 Fixed unused-parameters/unused-variables warnings
Added a ARG_UNUSED macro in utils/magic.h, which
produces a simple cast to void to silence the warnings.
The reasons this is used as opposed to an attribute is
that most compilers should support this.
Besides this, the macro can be easily searched for in
the future to potentially remove (where possible) the
unused parameters.
2025-10-10 22:12:19 +02:00

661 lines
18 KiB
C

/* 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. */
{
ARG_UNUSED(window);
ARG_UNUSED(point);
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. */
{
ARG_UNUSED(window);
ARG_UNUSED(cmd);
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. */
{
ARG_UNUSED(window);
ARG_UNUSED(cmd);
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;
}