home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / intrvews / xgrab.lha / xgrab / ui / aview.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-04-25  |  15.9 KB  |  618 lines

  1. /**
  2.    GRAB Graph Layout and Browser System
  3.  
  4.    Copyright (c) 1989, Tera Computer Company
  5.  **/
  6.  
  7. /**
  8.    Implementation of 'graph attributes' window and user-defined
  9.    attributes display.
  10.  
  11.    The window gives a record for which attributes are displayed in the
  12.    user-defined attributes display.  It is a full-fledged X window, and can 
  13.    be moved, iconified, resized, etc.  It can also be deleted using one
  14.    of the buttons in the window.  If it is popped up again, it remembers
  15.    where it was when deleted and places itself at that location on the 
  16.    screen.  When it first appears, it must be dropped as other windows
  17.    are.
  18.  
  19.    By clicking at various locations in the graph attributes window, the
  20.    user can tell the program to display or not display certain edge or node
  21.    attributes.  When the user asks to see the attributes for an edge or a
  22.    node, a box with the desired values (as indicated in the graph
  23.    attributes window) is displayed above the underlying interactor aligned 
  24.    with the upper left corner of the aligner interactor.  The box will 
  25.    stay there until the user asks to see the attributes of another
  26.    node/edge or the asks for it to disappear.  Currently, the box is an
  27.    independent window, so it doesn't move/hide/iconfify with the underlying
  28.    interactor (the xgrab window), which may be disconcerting.
  29.  **/
  30.  
  31. #include "istring.h"
  32. #include "aview.h"
  33. #include <InterViews/box.h>
  34. #include <InterViews/border.h>
  35. #include <InterViews/button.h>
  36. #include <InterViews/defs.h>
  37. #include <InterViews/frame.h>
  38. #include <InterViews/menu.h>
  39. #include <InterViews/event.h>
  40. #include <InterViews/interactor.h>
  41. #include <InterViews/message.h>
  42. #include <InterViews/glue.h>
  43. #include <InterViews/sensor.h>
  44. #include <InterViews/world.h>
  45. #include <stdio.h>
  46. #include <string.h>
  47.  
  48. extern World* world;
  49.  
  50. AView::AView (Interactor* in, Interactor* in2) : ()
  51.   /**
  52.      initialize the view of user-defined attributes.
  53.      in is the interactor which the user-defined attributes display is
  54.        layed over.  The display is aligned with the upper-left corner
  55.        of in2
  56.      values for the attribute names are set in SetAttrNames.  The display
  57.        cannot be set up until the names are known
  58.    **/
  59. {
  60.     underlying = in;
  61.     aligner = in2;
  62.  
  63.     node_attr_names = nil;
  64.     edge_attr_names = nil;
  65.     num_node_attr = num_edge_attr = 0;
  66.     node_attr_displayed = edge_attr_displayed = nil;
  67.  
  68.     NAttrMenu = nil;
  69.     EAttrMenu = nil;
  70.     NMenuBox = nil;
  71.     EMenuBox = nil;
  72.     currshow = nil;
  73.     Displayer = nil;
  74.     es = ec = ns = nc = eb = nil;
  75.  
  76.     onscreen = false;        /* it's not onscreen */
  77.     neveron = true;        /* and it hasn't been before */
  78.     oldx = oldy = 0;
  79.  
  80.     SetCanvasType(CanvasSaveUnder);    /* for quick redraw */
  81.     SetName("graph attributes");    /* window name */
  82.     input = allEvents;
  83. }
  84.  
  85. static const int horizsep = 10;    /* min #of pixels between objects in x dir */
  86. static const int vertsep = 10;    /* min #of pixels between objects in y dir */
  87.  
  88.   /* class names used to identify who received an event */
  89. static const char* atextitemname = "AttrTextItem";    
  90. static const char* pbuttonname = "PressButton";
  91.  
  92. void AView::SetAttrNames(char** nattr, char** eattr, int num_nattr, 
  93.     int num_eattr)
  94.   /**
  95.      Initialize the node and edge attribute names.  num_nattr and num_eattr
  96.      indicate the size of the arrays nattr and eattr
  97.    **/
  98. {
  99.     int i;
  100.  
  101.     if (onscreen)
  102.       /* if the graph attributes window is onscreen, it must be removed */
  103.     {
  104.     Shape *s = GetShape();
  105.         oldx = 0;        /* remember the upper-left coordinates */
  106.     oldy = s->height;
  107.         GetRelative(oldx, oldy, world);
  108.         world->Remove(this);
  109.     }
  110.  
  111.     if (Displayer != nil)
  112.       /* if there is an old displayer, remove it */
  113.     {
  114.     Remove(Displayer);
  115.     }
  116.  
  117.       /* throw out the old */
  118.     for (i = 0; i < num_node_attr; i++)
  119.     {
  120.     delete node_attr_names[i];
  121.     }
  122.  
  123.     for (i = 0; i < num_edge_attr; i++)
  124.     {
  125.     delete edge_attr_names[i];
  126.     }
  127.  
  128.     delete[num_node_attr] node_attr_displayed;
  129.     delete[num_edge_attr] edge_attr_displayed;
  130.     delete[num_node_attr] node_attr_names;
  131.     delete[num_edge_attr] edge_attr_names;
  132.  
  133.       /* make room for the new */
  134.     node_attr_names = new char *[num_nattr];
  135.     edge_attr_names = new char *[num_eattr];
  136.     num_node_attr = num_nattr;
  137.     num_edge_attr = num_eattr;
  138.  
  139.     node_attr_displayed = new boolean[num_nattr];
  140.     edge_attr_displayed = new boolean[num_eattr];
  141.  
  142.       /* initialize */
  143.     for (i = 0; i < num_nattr; i++)
  144.     {
  145.     node_attr_displayed[i] = false;
  146.     node_attr_names[i] = strdup(nattr[i]);
  147.     }
  148.  
  149.     for (i = 0; i < num_eattr; i++)
  150.     {
  151.     edge_attr_displayed[i] = false;
  152.     edge_attr_names[i] = strdup(eattr[i]);
  153.     }
  154.  
  155.       /* set up the menus and the boxes around them */
  156.     NAttrMenu = NewNodeMenu();
  157.     EAttrMenu = NewEdgeMenu();
  158.     NMenuBox = new HBox(NAttrMenu);
  159.     EMenuBox = new HBox(EAttrMenu);
  160.  
  161.       /* set up the buttons */
  162.     ec = new PressButton("Edge Clear", new ButtonState(), 4, this);
  163.     nc = new PressButton("Node Clear", new ButtonState(), 3, this);
  164.     es = new PressButton("Edge Setall", new ButtonState(), 2, this);
  165.     ns = new PressButton("Node Setall", new ButtonState(), 1, this);
  166.     eb = new PressButton("Close", new ButtonState(), 5, this);
  167.  
  168.       /* build the displayer */
  169.     HBox* AButtons = new HBox(new HGlue(horizsep), ns, new HGlue(horizsep), nc, 
  170.                   new HGlue(horizsep), es, new HGlue(horizsep));
  171.     AButtons->Insert(ec);
  172.     AButtons->Insert(new HGlue(horizsep));
  173.     HBox* AMenus = new HBox(new HGlue(horizsep), new Frame(NMenuBox), 
  174.                 new HGlue(horizsep), new Frame(EMenuBox), 
  175.                 new HGlue(horizsep));
  176.     Frame* d = new Frame(new VBox(new VGlue(vertsep), AMenus, 
  177.                   new VGlue(vertsep), AButtons,
  178.                   new VGlue(vertsep), 
  179.                   new HBox(new HGlue(horizsep), eb, 
  180.                            new HGlue(horizsep)), 
  181.                   new VGlue(vertsep)));
  182.  
  183.       /* add the displayer to this (the graph attributes window) */
  184.     Displayer = d;
  185.     Insert(Displayer);
  186.     Change(Displayer);
  187.  
  188.     if (neveron)     /* call the standard X 'insert window' routine */
  189.     {
  190.         world->Insert(this);
  191.     neveron = false;
  192.     }
  193.     else         /* popup up the window where it was last time */
  194.     {
  195.         world->Insert(this, oldx, oldy, TopLeft);
  196.     }
  197.  
  198.     onscreen = true;
  199. }
  200.  
  201. void AView::ShowNAttr(char** node_attr)
  202.   /**
  203.      Show these node attributes (there should be num_node_attr of them)
  204.      in the user-defined graph attributes display
  205.    **/
  206. {
  207.     if (currshow != nil)
  208.       /* get rid of the old display, if it exists */
  209.     {
  210.     Disappear(currshow);
  211.     }
  212.  
  213.       /* build the box and a header */
  214.     VBox* show = new VBox();
  215.     show->Insert(new HBox(new HGlue(horizsep), new Message("node attributes"), 
  216.               new HGlue(horizsep)));
  217.     show->Insert(new HBorder);
  218.  
  219.       /* add the attributes which are marked as displayed */
  220.     for (int i = 0; i < num_node_attr; i++)
  221.     {
  222.     if (node_attr_displayed[i])
  223.     {
  224.         show->Insert(new HBox(new HGlue(horizsep/2, 0, 0),
  225.                   new Message(strdup(node_attr_names[i])),
  226.                   new HGlue(horizsep),
  227.                   new Message(strdup(node_attr[i])),
  228.                   new HGlue(horizsep/2, 0, 0)));
  229.         show->Insert(new HBorder);
  230.     }
  231.     }
  232.  
  233.       /* make it into a scene */
  234.     currshow = new MonoScene();
  235.     currshow->Listen(allEvents);
  236.     currshow->SetCanvasType(CanvasSaveUnder);    /* for quick redraw */
  237.     currshow->Insert(new Frame(show));
  238.  
  239.       /* popup it up on the screen */
  240.     Coord x, y;
  241.     aligner->Align(TopLeft, 0, 0, x, y);
  242.     PopUp(currshow, x, y, TopLeft);
  243. }
  244.  
  245. void AView::ShowEAttr(char** edge_attr)
  246.   /**
  247.      Show these edge attributes (there should be num_edge_atttr of them)
  248.      in the user-defined graph attributes display
  249.    **/
  250. {
  251.     if (currshow != nil)
  252.       /* get rid of the old uda display, if any */
  253.     {
  254.     Disappear(currshow);
  255.     }
  256.  
  257.       /* build a box with a header */
  258.     VBox* show = new VBox();
  259.     show->Insert(new HBox(new HGlue(horizsep), new Message("edge attributes"), 
  260.               new HGlue(horizsep)));
  261.     show->Insert(new HBorder);
  262.  
  263.       /* add the attributes which are displayed */
  264.     for (int i = 0; i < num_edge_attr; i++)
  265.     {
  266.     if (edge_attr_displayed[i])
  267.     {
  268.         show->Insert(new HBox(new HGlue(horizsep / 2, 0, 0),
  269.                   new Message(strdup(edge_attr_names[i])),
  270.                   new HGlue(horizsep),
  271.                   new Message(strdup(edge_attr[i])),
  272.                   new HGlue(horizsep / 2, 0, 0)));
  273.         show->Insert(new HBorder);
  274.     }
  275.     }
  276.  
  277.       /* make a scene */
  278.     currshow = new MonoScene();
  279.     currshow->Listen(allEvents);
  280.     currshow->SetCanvasType(CanvasSaveUnder);    /* for quick redraw */
  281.     currshow->Insert(new Frame(show));
  282.  
  283.       /* pop it up */
  284.     Coord x, y;
  285.     aligner->Align(TopLeft, 0, 0, x, y);
  286.     PopUp(currshow, x, y, TopLeft);
  287. }
  288.     
  289. void AView::EraseAttrBox()
  290.   /* erase the user-defined graph attributes display (if there is one) */
  291. {
  292.     if (currshow != nil)
  293.     {
  294.     Disappear(currshow);
  295.     currshow = nil;
  296.     }
  297. }
  298.  
  299. static const char* on = "*";    /* indicates this attribute is displayed */
  300. static const char* off = " ";    /* indicates this one is not */
  301. static const edge_base = 5000;    
  302.   /** 
  303.      every attribute menu item has a distinguishing tag.  Add this value to
  304.      edge tags so we can easily tell edge items from node items.  There 
  305.      are more elegant ways to do this, but I doubt there will ever be any
  306.      greph with 5000 node attributes, so it shouldn't break
  307.    **/
  308.  
  309. boolean AView::SetDisplayed()
  310.   /**
  311.      Display the graph attributes window.  If it's already on screen,
  312.      return false, else display it and return true
  313.    **/
  314. {
  315.     if (!onscreen)
  316.     {
  317.     if (neveron)
  318.       /* call the standard X 'insert window' routine */
  319.     {
  320.         world->Insert(this);
  321.         neveron = false;
  322.         }
  323.         else
  324.         {
  325.       /* put it in the same place it was last time */
  326.             world->Insert(this, oldx, oldy, TopLeft);
  327.         }
  328.  
  329.     onscreen = true;
  330.         return true;
  331.     }
  332.     else
  333.     {
  334.     return false;
  335.     }
  336. }
  337.  
  338. void AView::Handle(Event& e)
  339.   /**
  340.      we only care about events which occur in buttons or attribute menu
  341.      items.  If this event did, pass it on.  If not, throw it away
  342.    **/
  343. {
  344.     if (e.target->GetClassName() != nil &&
  345.     (!strcmp(e.target->GetClassName(), pbuttonname) ||
  346.       !strcmp(e.target->GetClassName(), atextitemname)))
  347.     {
  348.     e.target->Handle(e);
  349.     }
  350. }
  351.  
  352. void AView::PopUp(Scene* scene, Coord x, Coord y, Alignment align)
  353.   /* Pop up scene at location x, y with alignment align */
  354. {
  355.     World* world = underlying->GetWorld();
  356.     aligner->GetRelative(x, y, world);
  357.     world->InsertTransient(scene, underlying, x, y, align);
  358. }
  359.  
  360. void AView::Disappear(Scene* scene)
  361.   /* remove the scene from view */
  362. {
  363.     scene->Parent()->Remove(scene);
  364. }
  365.  
  366. void AView::DoExit()
  367.   /* remove the graph attributes window from the screen */
  368. {
  369.     if (onscreen)
  370.     {
  371.     Shape *s = GetShape();
  372.  
  373.         oldx = 0;        /* save the old values for next time */
  374.     oldy = s->height;
  375.         GetRelative(oldx, oldy, world);
  376.         world->Remove(this);
  377.     onscreen = false;
  378.     }
  379. }
  380.  
  381. void AView::DoNodeSetall()
  382.   /* mark all the node attributes as 'displayed' */
  383. {
  384.     for (int i = 0; i < num_node_attr; i++)
  385.     {
  386.     node_attr_displayed[i] = true;
  387.     }
  388.  
  389.       /* redisplay the node attributes menu */
  390.     DisplayNAttrMenu();
  391. }
  392.  
  393. void AView::DoEdgeSetall()
  394.   /* mark all the edge attributes as 'displayed' */
  395. {
  396.     for (int i = 0; i < num_edge_attr; i++)
  397.     {
  398.     edge_attr_displayed[i] = true;
  399.     }
  400.  
  401.       /* redisplay the edge attributes menu */
  402.     DisplayEAttrMenu();
  403. }
  404.  
  405. void AView::DoNodeClear()
  406.   /* mark all the node attributes as not displayed */
  407. {
  408.     for (int i = 0; i < num_node_attr; i++)
  409.     {
  410.     node_attr_displayed[i] = false;
  411.     }
  412.  
  413.     DisplayNAttrMenu();
  414. }
  415.  
  416. void AView::DoEdgeClear()
  417.   /* mark all the edge attributes as not displayed */
  418. {
  419.     for (int i = 0; i < num_edge_attr; i++)
  420.     {
  421.     edge_attr_displayed[i] = false;
  422.     }
  423.  
  424.     DisplayEAttrMenu();
  425. }
  426.  
  427. void AView::SetClear(int val)
  428.   /**
  429.      called by a PressButton when it has been pressed.  The button sends
  430.      its identifying value, by which we can tell which routine to execute
  431.    **/
  432. {
  433.     switch(val)
  434.     {
  435.     case 1: 
  436.         DoNodeSetall();
  437.         break;
  438.     case 2:
  439.         DoEdgeSetall();
  440.         break;
  441.     case 3:
  442.         DoNodeClear();
  443.         break;
  444.     case 4:
  445.         DoEdgeClear();
  446.         break;
  447.     case 5:
  448.         DoExit();
  449.         break;
  450.     default:
  451.         break;
  452.     }
  453. }
  454.  
  455. void AView::ChangeAttr(int val)
  456.   /** 
  457.      Called by an AttrTextItem when it has been pressed.  The item sends
  458.      its identifying value, by which we can tell which attribute to change.
  459.      The attribute is marked as displayed if it wasn't, as not displayed if
  460.      it was.
  461.    **/
  462. {
  463.     if (val < edge_base)
  464.       /* it's a node attribute */
  465.     {
  466.     node_attr_displayed[val] = !node_attr_displayed[val];
  467.     DisplayNAttrMenu();
  468.     }
  469.     else
  470.       /* it's an edge attribute */
  471.     {
  472.     edge_attr_displayed[val - edge_base] = 
  473.       !edge_attr_displayed[val - edge_base];
  474.     DisplayEAttrMenu();
  475.     }
  476. }
  477.  
  478.   /**
  479.      The node menu and edge menu are both boxes within boxes because they
  480.      change so often.  With the surrounding box (NMenuBox or EMenuBox), it
  481.      is possible to remove the menu and put in a new one without
  482.      drastically affecting the layout of the graph attributes window.
  483.      InterViews boxes are very linear in nature; new items always go on the
  484.      right or bottom (depending on if it's an HBox or VBox).  So, when
  485.      an attribute is changed, it's best to rebuild the whole menu, which
  486.      means the menu must be removed.  In order to insure it's put back
  487.      where in the same relative location, it must be the only member in its
  488.      box.
  489.    **/
  490.      
  491. void AView::DisplayNAttrMenu()
  492.   /* display the node attribute menu */
  493. {
  494.     VBox* m = NewNodeMenu();
  495.     NMenuBox->Remove(NAttrMenu);
  496.     NAttrMenu = m;
  497.     NMenuBox->Insert(NAttrMenu);
  498.     NMenuBox->Change(NAttrMenu);
  499.     NMenuBox->Draw();
  500. }
  501.  
  502. void AView::DisplayEAttrMenu()
  503.   /* display the edge attribute menu */
  504. {
  505.     VBox* m = NewEdgeMenu();
  506.     EMenuBox->Remove(EAttrMenu);
  507.     EAttrMenu = m;
  508.     EMenuBox->Insert(EAttrMenu);
  509.     EMenuBox->Change(EAttrMenu);
  510.     EMenuBox->Draw();
  511. }
  512.  
  513. VBox* AView::NewNodeMenu()
  514.   /* build a new node menu */
  515. {
  516.     VBox *m;
  517.  
  518.     m = new VBox;
  519.     InsertNodeMenuItems(m);
  520.     return m;
  521. }
  522.  
  523. VBox* AView::NewEdgeMenu()
  524.   /* build a new edge menu */
  525. {
  526.     VBox *m;
  527.  
  528.     m = new VBox;
  529.     InsertEdgeMenuItems(m);
  530.     return m;
  531. }
  532.  
  533. static const int maxname = 100;    /* no strings longer than this allowed */
  534.  
  535. void AView::InsertNodeMenuItems(VBox* m)
  536.   /**
  537.      insert the node menu items, with an indication of whether they
  538.      are displayed or not
  539.    **/
  540. {
  541.     int i;
  542.     char* buf;
  543.  
  544.     for (i = 0; i < num_node_attr; i++)
  545.     {
  546.     buf = new char[maxname + 1];
  547.  
  548.     strcpy(buf, node_attr_displayed[i] ? on : off);
  549.     m->Insert(new AttrTextItem(strncat(buf, node_attr_names[i], 
  550.                        maxname - 1), 
  551.                    i, this));
  552.     m->Insert(new HBorder);
  553.     }
  554. }
  555.  
  556. void AView::InsertEdgeMenuItems(VBox* m)
  557.   /**
  558.      insert the edge menu items, with an indication of whether they
  559.      are displayed or not
  560.    **/
  561. {
  562.     int i;
  563.     char* buf;
  564.  
  565.     for (i = 0; i < num_edge_attr; i++)
  566.     {
  567.     buf = new char[maxname + 1];
  568.  
  569.     strcpy(buf, edge_attr_displayed[i] ? on : off);
  570.     m->Insert(new AttrTextItem(strncat(buf, edge_attr_names[i],
  571.                        maxname - 1), 
  572.                        edge_base + i, this));
  573.     m->Insert(new HBorder);
  574.     }
  575. }
  576.  
  577. AttrTextItem::AttrTextItem(char* s, int t, AView* h) : (s, t)
  578.   /**
  579.      A text item that calls a routine in the graph attributes window
  580.      when its handler is called.  t is an identifying tag so the handler
  581.      can tell which attribute we are
  582.    **/
  583. {
  584.     SetClassName(atextitemname);
  585.     handler = h;
  586.     value = t;
  587.     input = allEvents;
  588. }
  589.  
  590. void AttrTextItem::Handle (Event& e)
  591. {
  592.     if (e.eventType == UpEvent)
  593.     {
  594.         handler->ChangeAttr(value);
  595.     }
  596. }
  597.  
  598. PressButton::PressButton (char* s, ButtonState* b, int t, AView* h) 
  599.     : (s, b, -1) 
  600.   /**
  601.      A button that calls a routine in the graph attributes window
  602.      when its handler is called.  t is an identifying tag so the handler
  603.      can tell which attribute we are
  604.    **/
  605. {
  606.     SetClassName(pbuttonname);
  607.     handler = h;
  608.     value = t;
  609. }
  610.  
  611. void PressButton::Handle (Event& e) 
  612. {
  613.     if (e.eventType == UpEvent)
  614.     {
  615.     handler->SetClear(value);
  616.     }
  617. }
  618.