magic/netmenu/NMmain.c

574 lines
17 KiB
C

/* NMmain.c -
*
* This file defines the interface between the netlist
* editor and the window package. Most of the routines in
* here are called only by the window package. They are
* used for creating, deleting, and moving windows, for
* redisplay, and for top-level command interpretation.
* All the REAL work of commands goes on in other files.
*
* *********************************************************************
* * 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/NMmain.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "windows/windows.h"
#include "graphics/graphics.h"
#include "graphics/glyphs.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "dbwind/dbwind.h"
#include "textio/textio.h"
#include "utils/styles.h"
#include "textio/txcommands.h"
#include "netmenu/nmInt.h"
#include "netmenu/netmenu.h"
#include "utils/undo.h"
global WindClient NMClientID;
/* Forward declaration: */
extern void nmNotDefined();
/* The declarations below define the layout of the netlist
* window. Everything is defined in "surface" coordinates,
* not screen coordinates. Within each of the three categories,
* things are in order from top to bottom. Note: the order of
* the buttons is important, since they are referred to by index
* for specific purposes. See nmInt.h.
*/
NetButton NMButtons[] =
{
{NULL, STYLE_ORANGE1, {{0, 200}, {80, 210}},
NMGetLabels, NULL, NMNextLabel, NULL, NMNextLabel, NULL},
{NULL, STYLE_ERASEALL, {{0, 174}, {24, 198}},
NMPutLabel, NULL, NMReOrientLabel, NULL, NMReOrientLabel, NULL},
{NULL, STYLE_ORANGE1, {{42, 188}, {59, 198}},
NMChangeNum, NULL, NMChangeNum, NULL, NMChangeNum, NULL},
{NULL, STYLE_ORANGE1, {{63, 188}, {80, 198}},
NMChangeNum, NULL, NMChangeNum, NULL, NMChangeNum, NULL},
{"Find", STYLE_ORANGE2, {{42, 174}, {80, 184}},
NMFindLabel, NULL, NMFindLabel, NULL, NMFindLabel, NULL},
{NULL, STYLE_GREEN1, {{0, 150}, {80, 160}},
NMButtonNetList, NULL, NMButtonNetList, NULL, NMButtonNetList, NULL},
{"Verify", STYLE_BLUE1, {{0, 138}, {38, 148}},
NMCmdVerify, NULL, NMCmdVerify, NULL, NMCmdVerify, NULL},
{"Print", STYLE_BLUE2, {{42, 138}, {80, 148}},
NMCmdPrint, NULL, NMCmdPrint, NULL, NMCmdPrint, NULL},
{"Terms", STYLE_RED1, {{0, 126}, {38, 136}},
NMCmdShowterms, NULL, NMCmdShowterms, NULL, NMCmdShowterms, NULL},
{"Cleanup", STYLE_RED2, {{42, 126}, {80, 136}},
NMCmdCleanup, NULL, NMCmdCleanup, NULL, NMCmdCleanup, NULL},
{"No Net",STYLE_GRAY1, {{0, 114}, {38, 124}},
NMCmdDnet, NULL, NMCmdDnet, NULL, NMCmdDnet, NULL},
{"Show",STYLE_YELLOW1, {{42, 114}, {80, 124}},
NMShowUnderBox, NULL, NMShowUnderBox, NULL, NMShowUnderBox, NULL},
{NULL, -1 /* -1 Signals end of list. */ }
};
NetLabel nmLabels[] =
{
{"Label", STYLE_WHITE, {{0, 212}, {80, 222}}},
{"Netlist", STYLE_WHITE, {{0, 162}, {80, 172}}},
{NULL, -1 /* -1 signals end of list. */ }
};
NetRect nmRects[] =
{
{STYLE_BBOX, {{8, 174}, {16, 198}}},
{STYLE_BBOX, {{0, 182}, {24, 190}}},
{STYLE_BBOX, {{12, 186}, {12, 186}}},
{-1 /* -1 signals end of list. */ }
};
/* The following definitions are for the total surface area of the
* netlist menu, and the initial screen location of netlist menus.
*/
Rect nmSurfaceArea = {{-4, 110}, {84, 226}};
Rect nmScreenArea = {{0, 0}, {140, 190}};
/* Only one netlist window is allowed to be open at once. This is it. */
MagWindow *NMWindow = NULL;
/*
* ----------------------------------------------------------------------------
*
* NMcreate --
*
* Called by the window package when the user tries to create
* a new netlist window.
*
* Results:
* FALSE if there's already a netlist window: we only allow
* one at a time. TRUE is returned otherwise.
*
* Side effects:
* Sets the size and location of the window.
*
* ----------------------------------------------------------------------------
*/
/* ARGSUSED */
bool
NMcreate(window, argc, argv)
MagWindow *window; /* Partially-created window. */
int argc; /* Count of additional arguments. */
char *argv[]; /* Pointers to additional arguments. */
{
if (argc > 0)
TxError("Ignoring extra argments for netlist menu creation.\n");
if (NMWindow != NULL)
{
TxError("Sorry, can't have more than one netlist menu at a time.\n");
return FALSE;
}
NMWindow = window;
WindCaption(window, "NETLIST MENU");
window->w_frameArea = nmScreenArea;
window->w_flags &= ~(WIND_SCROLLABLE | WIND_SCROLLBARS | WIND_CAPTION);
WindSetWindowAreas(window);
WindMove(window, &nmSurfaceArea);
return TRUE;
}
/*
* ----------------------------------------------------------------------------
*
* NMdelete --
*
* This procedure is invoked by the window package just before
* the window is deleted, so we can clean things up before they
* go away.
*
* Results:
* None.
*
* Side effects:
* Nothing happens except to record that there's no longer an
* active netlist menu.
*
* ----------------------------------------------------------------------------
*/
/* ARGSUSED */
bool
NMdelete(window)
MagWindow *window; /* The window that's about to disappear. */
{
NMWindow = NULL;
NMClearPoints();
return TRUE;
}
/*
* ----------------------------------------------------------------------------
*
* NMreposition --
*
* This procedure is called by the window package when the netlist
* menu is being repositioned or resized. It gives us a chance to
* modify the final position, or at least clean ourselves up in
* accordance with the move.
*
* Results:
* None.
*
* Side effects:
* The window's view is changed so that the menu fits comfortably
* within it.
*
* ----------------------------------------------------------------------------
*/
/* ARGSUSED */
int
NMreposition(window, newScreenArea, final)
MagWindow *window; /* Window being repositioned. */
Rect *newScreenArea; /* New screen area of window. */
bool final; /* FALSE means the new area is
* tentative, and we can modify it
* (we never do). TRUE means this
* is our opportunity for final
* cleanup.
*/
{
if (final) WindMove(window, &nmSurfaceArea);
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* NMredisplay --
*
* This window is called, either by the window package or by
* other routines in this module, when part or all of the netlist
* menu needs to be redisplayed. It sets and clears its own
* window lock.
*
* Results:
* Return 0 always.
*
* Side effects:
* The given area of the window is redisplayed.
*
* ----------------------------------------------------------------------------
*/
int
NMredisplay(w, rootArea, clipArea)
MagWindow *w; /* The window containing the area. */
Rect *rootArea; /* Redisplay area in surface coordinates. */
Rect *clipArea; /* Screen area to clip to. If NULL, use
* screen area of window. */
{
Rect clip, screenR;
Point screenP;
NetButton *nb;
NetLabel *nl;
NetRect *nr;
/* Make sure that there's really a netlist window! (This procedure
* can be called before the window exists).
*/
if (NMWindow == (MagWindow *) NULL) return 0;
GrLock(w, TRUE);
/* Transform root area to the screen, then erase previous stuff
* in that area.
*/
if (clipArea != NULL) clip = *clipArea;
else clip = GrScreenRect;
GrClipTo(&clip);
WindSurfaceToScreen(w, rootArea, &screenR);
GrClipBox(&screenR, STYLE_ERASEALL);
GrClipBox(&screenR, STYLE_PURPLE);
/* Redisplay each of the buttons. */
for (nb = NMButtons; nb->nmb_style >= 0; nb++)
{
if (GEO_TOUCH(&nb->nmb_area, rootArea))
{
WindSurfaceToScreen(w, &nb->nmb_area, &screenR);
/* Erase the area of the button before redrawing. This is
* needed on monochrome displays, or else the purple will
* OR in with the button color.
*/
GrClipBox(&screenR, STYLE_ERASEALL);
GrClipBox(&screenR, nb->nmb_style);
GrClipBox(&screenR, STYLE_BBOX);
if (nb->nmb_text != NULL)
{
screenP.p_x = (screenR.r_xbot + screenR.r_xtop)/2;
screenP.p_y = (screenR.r_ybot + screenR.r_ytop)/2;
screenR.r_xbot += 1;
screenR.r_ybot += 1;
screenR.r_xtop -= 1;
screenR.r_ytop -= 1;
GrClipTo(&GrScreenRect);
GrPutText(nb->nmb_text, STYLE_BBOX, &screenP,
GEO_CENTER, GR_TEXT_MEDIUM, TRUE, &screenR, (Rect *) NULL);
GrClipTo(&clip);
}
}
}
/* Redisplay each of the decorative labels. */
GrClipTo(&GrScreenRect);
for (nl = nmLabels; nl->nml_style >= 0; nl++)
{
if (GEO_TOUCH(&nl->nml_area, rootArea))
{
WindSurfaceToScreen(w, &nl->nml_area, &screenR);
screenP.p_x = (screenR.r_xbot + screenR.r_xtop)/2;
screenP.p_y = (screenR.r_ybot + screenR.r_ytop)/2;
screenR.r_xbot += 1;
screenR.r_ybot += 1;
screenR.r_xtop -= 1;
screenR.r_ytop -= 1;
GrPutText(nl->nml_text, nl->nml_style, &screenP,
GEO_CENTER, GR_TEXT_MEDIUM, TRUE, &screenR, (Rect *) NULL);
}
}
GrClipTo(&clip);
/* Redisplay each of the decorative rectangles. */
for (nr = nmRects; nr->nmr_style >= 0; nr++)
{
if (GEO_TOUCH(&nr->nmr_area, rootArea))
{
WindSurfaceToScreen(w, &nr->nmr_area, &screenR);
GrClipBox(&screenR, nr->nmr_style);
}
}
GrUnlock(w);
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* NMcommand --
*
* This procedure is called by the window package whenever a
* button is pressed with the cursor inside the netlist menu.
*
* Results:
* Return 0 always.
*
* Side effects:
* If the cursor is over one of the buttons, the corresponding
* command routine (if any) is called. Otherwise, nothing is
* done.
*
* ----------------------------------------------------------------------------
*/
int
NMcommand(w, cmd)
MagWindow *w; /* Net-list menu window. */
TxCommand *cmd;
{
NetButton *nb;
Point surfacePoint;
void (*proc)();
int cmdNum;
if (cmd->tx_button == TX_NO_BUTTON)
{
WindExecute(w, NMClientID, cmd);
goto done;
}
if (w == NULL) return 0;
WindPointToSurface(w, &cmd->tx_p, &surfacePoint, (Rect *) NULL);
/* Since some of the command routines are invoked both in
* response to buttons and in response to typed commands,
* fake the presence of a single command keyword.
*/
cmd->tx_argc = 1;
cmd->tx_argv[0] = "";
/* See if the cursor is over any of the buttons. */
for (nb = NMButtons; nb->nmb_style >= 0; nb++)
{
if (GEO_ENCLOSE(&surfacePoint, &nb->nmb_area))
{
/* Pick the appropriate procedure for this button action,
* then invoke it (if it exists).
*/
proc = NULL;
switch (cmd->tx_buttonAction)
{
case TX_BUTTON_DOWN:
switch (cmd->tx_button)
{
case TX_LEFT_BUTTON:
proc = nb->nmb_leftDown;
break;
case TX_MIDDLE_BUTTON:
proc = nb->nmb_middleDown;
break;
case TX_RIGHT_BUTTON:
proc = nb->nmb_rightDown;
break;
}
break;
case TX_BUTTON_UP:
switch (cmd->tx_button)
{
case TX_LEFT_BUTTON:
proc = nb->nmb_leftUp;
break;
case TX_MIDDLE_BUTTON:
proc = nb->nmb_middleUp;
break;
case TX_RIGHT_BUTTON:
proc = nb->nmb_rightUp;
break;
}
break;
}
if (proc != NULL) (*proc)(w, cmd, nb, &surfacePoint);
}
}
done:
UndoNext();
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* NWinit --
*
* Called by Magic's main program once at the very beginning
* so this module can initialize itself.
*
* Results:
* None.
*
* Side effects:
* Add this module to the window package's list of registered
* clients, and to the undo package.
*
* ----------------------------------------------------------------------------
*/
void
NMinit()
{
static char *doc = "You are currently using the \"netlist\" tool."
" The button actions are:\n"
" left - select the net containing the terminal"
" nearest the cursor\n"
" right - toggle the terminal nearest the cursor"
" into/out of current net\n"
" middle - join current net and net containing terminal"
" nearest the cursor\n";
NMClientID = WindAddClient("netlist", NMcreate, NMdelete,
NMredisplay, NMcommand, (void(*)())NULL,
NMCheckWritten, NMreposition,
(GrGlyph *)NULL);
DBWHLAddClient(NMRedrawPoints);
DBWHLAddClient(NMRedrawCell);
DBWAddButtonHandler("netlist", NMButtonProc, STYLE_CURS_NET, doc);
NMUndoInit();
/* Register commands with the client */
WindAddCommand(NMClientID,
"add term1 term2 add term1 to net of term2",
NMCmdAdd, FALSE);
WindAddCommand(NMClientID,
"cleanup interactively cleanup netlist",
NMCmdCleanup, FALSE);
WindAddCommand(NMClientID,
"cull remove fully-wired nets from the current netlist",
NMCmdCull, FALSE);
WindAddCommand(NMClientID,
"dnet name name ... delete the net(s) containing name(s)\n\
or current net if no name(s) given",
NMCmdDnet, FALSE);
WindAddCommand(NMClientID,
"dterm name name ... delete terminals from nets",
NMCmdDterm, FALSE);
WindAddCommand(NMClientID,
"extract generate net for terminals connected to box",
NMCmdExtract, FALSE);
WindAddCommand(NMClientID,
"find pattern [layers] find all occurrences of any labels matching\n\
pattern beneath the box (on layers if specified)\n\
and leave as feedback",
NMCmdFindLabels, FALSE);
WindAddCommand(NMClientID,
"flush [netlist] flush changes to netlist (current list default)",
NMCmdFlush, FALSE);
WindAddCommand(NMClientID,
"joinnets term1 term2 join the nets containing term1 and term2",
NMCmdJoinNets, FALSE);
WindAddCommand(NMClientID,
"netlist [name] switch current netlist to name.net (default\n\
is edit cell name)",
NMCmdNetlist, FALSE);
WindAddCommand(NMClientID,
"pushbutton button execute the default button action in the netlist\n\
window.",
NMCmdPushButton, FALSE);
WindAddCommand(NMClientID,
"print [name] print all terminals in name, or in current net\n\
if no name given",
NMCmdPrint, FALSE);
WindAddCommand(NMClientID,
"ripup [netlist] ripup edit cell paint connected to paint under\n\
box, or ripup current netlist if \"netlist\"\n\
typed as argument",
NMCmdRipup, FALSE);
WindAddCommand(NMClientID,
"savenetlist [file] write out current netlist",
NMCmdSavenetlist, FALSE);
WindAddCommand(NMClientID,
"shownet highlight edit cell paint connected to paint\n\
under box",
NMCmdShownet, FALSE);
WindAddCommand(NMClientID,
"showterms generate feedback for all terminals in netlist",
NMCmdShowterms, FALSE);
WindAddCommand(NMClientID,
"trace [name] highlight material connected to a net's \n\
terminals (use current net if no name given)",
NMCmdTrace, FALSE);
WindAddCommand(NMClientID,
"verify make sure current netlist is correctly wired",
NMCmdVerify, FALSE);
WindAddCommand(NMClientID,
"writeall write out all modified netlists",
NMCmdWriteall, FALSE);
}
/*
* ----------------------------------------------------------------------------
*
* nmNotDefined --
*
* This is a dummy command procedure for things that aren't
* implemented yet.
*
* Results:
* None.
*
* Side effects:
* Just prints out an error message that this command isn't implemented.
*
* ----------------------------------------------------------------------------
*/
void
nmNotDefined()
{
TxError("Sorry, no code has been written for that button yet.\n");
}