home *** CD-ROM | disk | FTP | other *** search
- /**
- GRAB Graph Layout and Browser System
-
- Copyright (c) 1989, Tera Computer Company
- **/
-
- /**
- Implementation of 'graph attributes' window and user-defined
- attributes display.
-
- The window gives a record for which attributes are displayed in the
- user-defined attributes display. It is a full-fledged X window, and can
- be moved, iconified, resized, etc. It can also be deleted using one
- of the buttons in the window. If it is popped up again, it remembers
- where it was when deleted and places itself at that location on the
- screen. When it first appears, it must be dropped as other windows
- are.
-
- By clicking at various locations in the graph attributes window, the
- user can tell the program to display or not display certain edge or node
- attributes. When the user asks to see the attributes for an edge or a
- node, a box with the desired values (as indicated in the graph
- attributes window) is displayed above the underlying interactor aligned
- with the upper left corner of the aligner interactor. The box will
- stay there until the user asks to see the attributes of another
- node/edge or the asks for it to disappear. Currently, the box is an
- independent window, so it doesn't move/hide/iconfify with the underlying
- interactor (the xgrab window), which may be disconcerting.
- **/
-
- #include "istring.h"
- #include "aview.h"
- #include <InterViews/box.h>
- #include <InterViews/border.h>
- #include <InterViews/button.h>
- #include <InterViews/defs.h>
- #include <InterViews/frame.h>
- #include <InterViews/menu.h>
- #include <InterViews/event.h>
- #include <InterViews/interactor.h>
- #include <InterViews/message.h>
- #include <InterViews/glue.h>
- #include <InterViews/sensor.h>
- #include <InterViews/world.h>
- #include <stdio.h>
- #include <string.h>
-
- extern World* world;
-
- AView::AView (Interactor* in, Interactor* in2) : ()
- /**
- initialize the view of user-defined attributes.
- in is the interactor which the user-defined attributes display is
- layed over. The display is aligned with the upper-left corner
- of in2
- values for the attribute names are set in SetAttrNames. The display
- cannot be set up until the names are known
- **/
- {
- underlying = in;
- aligner = in2;
-
- node_attr_names = nil;
- edge_attr_names = nil;
- num_node_attr = num_edge_attr = 0;
- node_attr_displayed = edge_attr_displayed = nil;
-
- NAttrMenu = nil;
- EAttrMenu = nil;
- NMenuBox = nil;
- EMenuBox = nil;
- currshow = nil;
- Displayer = nil;
- es = ec = ns = nc = eb = nil;
-
- onscreen = false; /* it's not onscreen */
- neveron = true; /* and it hasn't been before */
- oldx = oldy = 0;
-
- SetCanvasType(CanvasSaveUnder); /* for quick redraw */
- SetName("graph attributes"); /* window name */
- input = allEvents;
- }
-
- static const int horizsep = 10; /* min #of pixels between objects in x dir */
- static const int vertsep = 10; /* min #of pixels between objects in y dir */
-
- /* class names used to identify who received an event */
- static const char* atextitemname = "AttrTextItem";
- static const char* pbuttonname = "PressButton";
-
- void AView::SetAttrNames(char** nattr, char** eattr, int num_nattr,
- int num_eattr)
- /**
- Initialize the node and edge attribute names. num_nattr and num_eattr
- indicate the size of the arrays nattr and eattr
- **/
- {
- int i;
-
- if (onscreen)
- /* if the graph attributes window is onscreen, it must be removed */
- {
- Shape *s = GetShape();
- oldx = 0; /* remember the upper-left coordinates */
- oldy = s->height;
- GetRelative(oldx, oldy, world);
- world->Remove(this);
- }
-
- if (Displayer != nil)
- /* if there is an old displayer, remove it */
- {
- Remove(Displayer);
- }
-
- /* throw out the old */
- for (i = 0; i < num_node_attr; i++)
- {
- delete node_attr_names[i];
- }
-
- for (i = 0; i < num_edge_attr; i++)
- {
- delete edge_attr_names[i];
- }
-
- delete[num_node_attr] node_attr_displayed;
- delete[num_edge_attr] edge_attr_displayed;
- delete[num_node_attr] node_attr_names;
- delete[num_edge_attr] edge_attr_names;
-
- /* make room for the new */
- node_attr_names = new char *[num_nattr];
- edge_attr_names = new char *[num_eattr];
- num_node_attr = num_nattr;
- num_edge_attr = num_eattr;
-
- node_attr_displayed = new boolean[num_nattr];
- edge_attr_displayed = new boolean[num_eattr];
-
- /* initialize */
- for (i = 0; i < num_nattr; i++)
- {
- node_attr_displayed[i] = false;
- node_attr_names[i] = strdup(nattr[i]);
- }
-
- for (i = 0; i < num_eattr; i++)
- {
- edge_attr_displayed[i] = false;
- edge_attr_names[i] = strdup(eattr[i]);
- }
-
- /* set up the menus and the boxes around them */
- NAttrMenu = NewNodeMenu();
- EAttrMenu = NewEdgeMenu();
- NMenuBox = new HBox(NAttrMenu);
- EMenuBox = new HBox(EAttrMenu);
-
- /* set up the buttons */
- ec = new PressButton("Edge Clear", new ButtonState(), 4, this);
- nc = new PressButton("Node Clear", new ButtonState(), 3, this);
- es = new PressButton("Edge Setall", new ButtonState(), 2, this);
- ns = new PressButton("Node Setall", new ButtonState(), 1, this);
- eb = new PressButton("Close", new ButtonState(), 5, this);
-
- /* build the displayer */
- HBox* AButtons = new HBox(new HGlue(horizsep), ns, new HGlue(horizsep), nc,
- new HGlue(horizsep), es, new HGlue(horizsep));
- AButtons->Insert(ec);
- AButtons->Insert(new HGlue(horizsep));
- HBox* AMenus = new HBox(new HGlue(horizsep), new Frame(NMenuBox),
- new HGlue(horizsep), new Frame(EMenuBox),
- new HGlue(horizsep));
- Frame* d = new Frame(new VBox(new VGlue(vertsep), AMenus,
- new VGlue(vertsep), AButtons,
- new VGlue(vertsep),
- new HBox(new HGlue(horizsep), eb,
- new HGlue(horizsep)),
- new VGlue(vertsep)));
-
- /* add the displayer to this (the graph attributes window) */
- Displayer = d;
- Insert(Displayer);
- Change(Displayer);
-
- if (neveron) /* call the standard X 'insert window' routine */
- {
- world->Insert(this);
- neveron = false;
- }
- else /* popup up the window where it was last time */
- {
- world->Insert(this, oldx, oldy, TopLeft);
- }
-
- onscreen = true;
- }
-
- void AView::ShowNAttr(char** node_attr)
- /**
- Show these node attributes (there should be num_node_attr of them)
- in the user-defined graph attributes display
- **/
- {
- if (currshow != nil)
- /* get rid of the old display, if it exists */
- {
- Disappear(currshow);
- }
-
- /* build the box and a header */
- VBox* show = new VBox();
- show->Insert(new HBox(new HGlue(horizsep), new Message("node attributes"),
- new HGlue(horizsep)));
- show->Insert(new HBorder);
-
- /* add the attributes which are marked as displayed */
- for (int i = 0; i < num_node_attr; i++)
- {
- if (node_attr_displayed[i])
- {
- show->Insert(new HBox(new HGlue(horizsep/2, 0, 0),
- new Message(strdup(node_attr_names[i])),
- new HGlue(horizsep),
- new Message(strdup(node_attr[i])),
- new HGlue(horizsep/2, 0, 0)));
- show->Insert(new HBorder);
- }
- }
-
- /* make it into a scene */
- currshow = new MonoScene();
- currshow->Listen(allEvents);
- currshow->SetCanvasType(CanvasSaveUnder); /* for quick redraw */
- currshow->Insert(new Frame(show));
-
- /* popup it up on the screen */
- Coord x, y;
- aligner->Align(TopLeft, 0, 0, x, y);
- PopUp(currshow, x, y, TopLeft);
- }
-
- void AView::ShowEAttr(char** edge_attr)
- /**
- Show these edge attributes (there should be num_edge_atttr of them)
- in the user-defined graph attributes display
- **/
- {
- if (currshow != nil)
- /* get rid of the old uda display, if any */
- {
- Disappear(currshow);
- }
-
- /* build a box with a header */
- VBox* show = new VBox();
- show->Insert(new HBox(new HGlue(horizsep), new Message("edge attributes"),
- new HGlue(horizsep)));
- show->Insert(new HBorder);
-
- /* add the attributes which are displayed */
- for (int i = 0; i < num_edge_attr; i++)
- {
- if (edge_attr_displayed[i])
- {
- show->Insert(new HBox(new HGlue(horizsep / 2, 0, 0),
- new Message(strdup(edge_attr_names[i])),
- new HGlue(horizsep),
- new Message(strdup(edge_attr[i])),
- new HGlue(horizsep / 2, 0, 0)));
- show->Insert(new HBorder);
- }
- }
-
- /* make a scene */
- currshow = new MonoScene();
- currshow->Listen(allEvents);
- currshow->SetCanvasType(CanvasSaveUnder); /* for quick redraw */
- currshow->Insert(new Frame(show));
-
- /* pop it up */
- Coord x, y;
- aligner->Align(TopLeft, 0, 0, x, y);
- PopUp(currshow, x, y, TopLeft);
- }
-
- void AView::EraseAttrBox()
- /* erase the user-defined graph attributes display (if there is one) */
- {
- if (currshow != nil)
- {
- Disappear(currshow);
- currshow = nil;
- }
- }
-
- static const char* on = "*"; /* indicates this attribute is displayed */
- static const char* off = " "; /* indicates this one is not */
- static const edge_base = 5000;
- /**
- every attribute menu item has a distinguishing tag. Add this value to
- edge tags so we can easily tell edge items from node items. There
- are more elegant ways to do this, but I doubt there will ever be any
- greph with 5000 node attributes, so it shouldn't break
- **/
-
- boolean AView::SetDisplayed()
- /**
- Display the graph attributes window. If it's already on screen,
- return false, else display it and return true
- **/
- {
- if (!onscreen)
- {
- if (neveron)
- /* call the standard X 'insert window' routine */
- {
- world->Insert(this);
- neveron = false;
- }
- else
- {
- /* put it in the same place it was last time */
- world->Insert(this, oldx, oldy, TopLeft);
- }
-
- onscreen = true;
- return true;
- }
- else
- {
- return false;
- }
- }
-
- void AView::Handle(Event& e)
- /**
- we only care about events which occur in buttons or attribute menu
- items. If this event did, pass it on. If not, throw it away
- **/
- {
- if (e.target->GetClassName() != nil &&
- (!strcmp(e.target->GetClassName(), pbuttonname) ||
- !strcmp(e.target->GetClassName(), atextitemname)))
- {
- e.target->Handle(e);
- }
- }
-
- void AView::PopUp(Scene* scene, Coord x, Coord y, Alignment align)
- /* Pop up scene at location x, y with alignment align */
- {
- World* world = underlying->GetWorld();
- aligner->GetRelative(x, y, world);
- world->InsertTransient(scene, underlying, x, y, align);
- }
-
- void AView::Disappear(Scene* scene)
- /* remove the scene from view */
- {
- scene->Parent()->Remove(scene);
- }
-
- void AView::DoExit()
- /* remove the graph attributes window from the screen */
- {
- if (onscreen)
- {
- Shape *s = GetShape();
-
- oldx = 0; /* save the old values for next time */
- oldy = s->height;
- GetRelative(oldx, oldy, world);
- world->Remove(this);
- onscreen = false;
- }
- }
-
- void AView::DoNodeSetall()
- /* mark all the node attributes as 'displayed' */
- {
- for (int i = 0; i < num_node_attr; i++)
- {
- node_attr_displayed[i] = true;
- }
-
- /* redisplay the node attributes menu */
- DisplayNAttrMenu();
- }
-
- void AView::DoEdgeSetall()
- /* mark all the edge attributes as 'displayed' */
- {
- for (int i = 0; i < num_edge_attr; i++)
- {
- edge_attr_displayed[i] = true;
- }
-
- /* redisplay the edge attributes menu */
- DisplayEAttrMenu();
- }
-
- void AView::DoNodeClear()
- /* mark all the node attributes as not displayed */
- {
- for (int i = 0; i < num_node_attr; i++)
- {
- node_attr_displayed[i] = false;
- }
-
- DisplayNAttrMenu();
- }
-
- void AView::DoEdgeClear()
- /* mark all the edge attributes as not displayed */
- {
- for (int i = 0; i < num_edge_attr; i++)
- {
- edge_attr_displayed[i] = false;
- }
-
- DisplayEAttrMenu();
- }
-
- void AView::SetClear(int val)
- /**
- called by a PressButton when it has been pressed. The button sends
- its identifying value, by which we can tell which routine to execute
- **/
- {
- switch(val)
- {
- case 1:
- DoNodeSetall();
- break;
- case 2:
- DoEdgeSetall();
- break;
- case 3:
- DoNodeClear();
- break;
- case 4:
- DoEdgeClear();
- break;
- case 5:
- DoExit();
- break;
- default:
- break;
- }
- }
-
- void AView::ChangeAttr(int val)
- /**
- Called by an AttrTextItem when it has been pressed. The item sends
- its identifying value, by which we can tell which attribute to change.
- The attribute is marked as displayed if it wasn't, as not displayed if
- it was.
- **/
- {
- if (val < edge_base)
- /* it's a node attribute */
- {
- node_attr_displayed[val] = !node_attr_displayed[val];
- DisplayNAttrMenu();
- }
- else
- /* it's an edge attribute */
- {
- edge_attr_displayed[val - edge_base] =
- !edge_attr_displayed[val - edge_base];
- DisplayEAttrMenu();
- }
- }
-
- /**
- The node menu and edge menu are both boxes within boxes because they
- change so often. With the surrounding box (NMenuBox or EMenuBox), it
- is possible to remove the menu and put in a new one without
- drastically affecting the layout of the graph attributes window.
- InterViews boxes are very linear in nature; new items always go on the
- right or bottom (depending on if it's an HBox or VBox). So, when
- an attribute is changed, it's best to rebuild the whole menu, which
- means the menu must be removed. In order to insure it's put back
- where in the same relative location, it must be the only member in its
- box.
- **/
-
- void AView::DisplayNAttrMenu()
- /* display the node attribute menu */
- {
- VBox* m = NewNodeMenu();
- NMenuBox->Remove(NAttrMenu);
- NAttrMenu = m;
- NMenuBox->Insert(NAttrMenu);
- NMenuBox->Change(NAttrMenu);
- NMenuBox->Draw();
- }
-
- void AView::DisplayEAttrMenu()
- /* display the edge attribute menu */
- {
- VBox* m = NewEdgeMenu();
- EMenuBox->Remove(EAttrMenu);
- EAttrMenu = m;
- EMenuBox->Insert(EAttrMenu);
- EMenuBox->Change(EAttrMenu);
- EMenuBox->Draw();
- }
-
- VBox* AView::NewNodeMenu()
- /* build a new node menu */
- {
- VBox *m;
-
- m = new VBox;
- InsertNodeMenuItems(m);
- return m;
- }
-
- VBox* AView::NewEdgeMenu()
- /* build a new edge menu */
- {
- VBox *m;
-
- m = new VBox;
- InsertEdgeMenuItems(m);
- return m;
- }
-
- static const int maxname = 100; /* no strings longer than this allowed */
-
- void AView::InsertNodeMenuItems(VBox* m)
- /**
- insert the node menu items, with an indication of whether they
- are displayed or not
- **/
- {
- int i;
- char* buf;
-
- for (i = 0; i < num_node_attr; i++)
- {
- buf = new char[maxname + 1];
-
- strcpy(buf, node_attr_displayed[i] ? on : off);
- m->Insert(new AttrTextItem(strncat(buf, node_attr_names[i],
- maxname - 1),
- i, this));
- m->Insert(new HBorder);
- }
- }
-
- void AView::InsertEdgeMenuItems(VBox* m)
- /**
- insert the edge menu items, with an indication of whether they
- are displayed or not
- **/
- {
- int i;
- char* buf;
-
- for (i = 0; i < num_edge_attr; i++)
- {
- buf = new char[maxname + 1];
-
- strcpy(buf, edge_attr_displayed[i] ? on : off);
- m->Insert(new AttrTextItem(strncat(buf, edge_attr_names[i],
- maxname - 1),
- edge_base + i, this));
- m->Insert(new HBorder);
- }
- }
-
- AttrTextItem::AttrTextItem(char* s, int t, AView* h) : (s, t)
- /**
- A text item that calls a routine in the graph attributes window
- when its handler is called. t is an identifying tag so the handler
- can tell which attribute we are
- **/
- {
- SetClassName(atextitemname);
- handler = h;
- value = t;
- input = allEvents;
- }
-
- void AttrTextItem::Handle (Event& e)
- {
- if (e.eventType == UpEvent)
- {
- handler->ChangeAttr(value);
- }
- }
-
- PressButton::PressButton (char* s, ButtonState* b, int t, AView* h)
- : (s, b, -1)
- /**
- A button that calls a routine in the graph attributes window
- when its handler is called. t is an identifying tag so the handler
- can tell which attribute we are
- **/
- {
- SetClassName(pbuttonname);
- handler = h;
- value = t;
- }
-
- void PressButton::Handle (Event& e)
- {
- if (e.eventType == UpEvent)
- {
- handler->SetClear(value);
- }
- }
-