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

  1. /**
  2.    GRAB Graph Layout and Browser System
  3.  
  4.    Copyright (c) 1987, 1988, 1989 Stanford University
  5.    Copyright (c) 1989, Tera Computer Company
  6.  **/
  7.  
  8.   /**
  9.      stolen from the InterViews 2.5 bin source files.  Dialogbox is a nice
  10.      way to enter a string.  This also contains the classes which allow
  11.      you to confirm an action
  12.    **/
  13.  
  14. #include "dialogbox.h"
  15. #include "istring.h"
  16. #include <InterViews/dialog.h>
  17. #include <InterViews/box.h>
  18. #include <InterViews/button.h>
  19. #include <InterViews/canvas.h>
  20. #include <InterViews/event.h>
  21. #include <InterViews/font.h>
  22. #include <InterViews/frame.h>
  23. #include <InterViews/glue.h>
  24. #include <InterViews/painter.h>
  25. #include <InterViews/sensor.h>
  26. #include <InterViews/shape.h>
  27. #include <InterViews/world.h>
  28.  
  29. // IMessage creates a buffer to store its own copy of the text.
  30.  
  31. IMessage::IMessage (const char* msg, Alignment a) : (nil, a) 
  32. {
  33.     buffer = strdup(msg ? msg : "");
  34.     text = buffer;
  35. }
  36.  
  37. // Free storage allocated for the text buffer.
  38.  
  39. IMessage::~IMessage () 
  40. {
  41.     delete buffer;
  42. }
  43.  
  44. // SetText stores the new text and changes the IMessage's shape to fit
  45. // the new text's width.
  46.  
  47. void IMessage::SetText (const char* beg, const char* end) 
  48. {
  49.     beg = beg ? beg : "";
  50.     end = end ? end : "";
  51.     delete buffer;
  52.     buffer = new char[strlen(beg) + strlen(end) + 1];
  53.     strcpy(buffer, beg);
  54.     strcat(buffer, end);
  55.     text = buffer;
  56.  
  57.     if (canvas != nil && canvas->Status() == CanvasMapped) 
  58.     {
  59.     Reconfig();
  60.     Parent()->Change(this);
  61.     }
  62. }
  63.  
  64. // DialogBox creates two IMessages to display a message and a warning
  65. // and stores its underlying Interactor.  DialogBox won't delete the
  66. // IMessages so its derived classes can put them in boxes which will
  67. // delete them when the boxes are deleted.
  68.  
  69. DialogBox::DialogBox (Interactor* u, const char* msg) 
  70. {
  71.     SetCanvasType(CanvasSaveUnder); // speed up expose redrawing if possible
  72.     input = allEvents;
  73.     input->Reference();
  74.     message = new IMessage(msg);
  75.     warning = new IMessage;
  76.     underlying = u;
  77. }
  78.  
  79. // SetMessage sets the message's text.
  80.  
  81. void DialogBox::SetMessage (const char* beg, const char* end) 
  82. {
  83.     message->SetText(beg, end);
  84. }
  85.  
  86. // SetWarning sets the warning's text.
  87.  
  88. void DialogBox::SetWarning (const char* beg, const char* end) 
  89. {
  90.     warning->SetText(beg, end);
  91. }
  92.  
  93. // SetUnderlying sets the underlying Interactor over which the
  94. // DialogBox will pop up itself.
  95.  
  96. void DialogBox::SetUnderlying (Interactor* u) 
  97. {
  98.     underlying = u;
  99. }
  100.  
  101. // PopUp pops up the DialogBox centered over the underlying
  102. // Interactor's canvas.
  103.  
  104. void DialogBox::PopUp () 
  105. {
  106.     World* world = underlying->GetWorld();
  107.     Coord x, y;
  108.     underlying->Align(Center, 0, 0, x, y);
  109.     underlying->GetRelative(x, y, world);
  110.     world->InsertTransient(this, underlying, x, y, Center);
  111. }
  112.  
  113. // Disappear removes the DialogBox.  Since the user should see
  114. // warnings only once, Disappear clears the warning's text so the next
  115. // PopUp won't display it.
  116.  
  117. void DialogBox::Disappear () 
  118. {
  119.     Parent()->Remove(this);
  120.     SetWarning();
  121.     Sync();
  122. }
  123.  
  124. // Messager creates its button state and initializes its view.
  125.  
  126. Messager::Messager (Interactor* u, const char* msg) : (u, msg) 
  127. {
  128.     ok = new ButtonState(false);
  129.     okbutton = new PushButton("  OK  ", ok, true);
  130.     Init();
  131. }
  132.  
  133. // Free storage allocated for the message's button state.
  134. // Okbutton detach itself from the button state when deleting itself
  135. // so we have to delete the state last of all.
  136.  
  137. Messager::~Messager () 
  138. {
  139.     delete ok;
  140. }
  141.  
  142. // Display pops up the Messager and removes it when the user
  143. // acknowledges the message.
  144.  
  145. void Messager::Display () 
  146. {
  147.     ok->SetValue(false);
  148.  
  149.     PopUp();
  150.  
  151.     int okay = false;
  152.     while (!okay) 
  153.     {
  154.     Event e;
  155.     Read(e);
  156.     if (e.eventType == KeyEvent && e.len > 0) 
  157.     {
  158.         switch (e.keystring[0]) 
  159.         {
  160.         case '\r':        // CR
  161.         case '\007':    // ^G
  162.         ok->SetValue(true);
  163.         break;
  164.         default:
  165.         break;
  166.         }
  167.     }
  168.     else if (e.target == okbutton) 
  169.     {
  170.         e.target->Handle(e);
  171.     }
  172.  
  173.     ok->GetValue(okay);
  174.     }
  175.  
  176.     Disappear();
  177. }
  178.  
  179. // Init composes Messager's view with boxes, glue, and frames.
  180.  
  181. void Messager::Init () 
  182. {
  183.     SetClassName("Messager");
  184.  
  185.     VBox* vbox = new VBox;
  186.     vbox->Align(Center);
  187.     vbox->Insert(new VGlue);
  188.     vbox->Insert(warning);
  189.     vbox->Insert(new VGlue);
  190.     vbox->Insert(message);
  191.     vbox->Insert(new VGlue);
  192.     vbox->Insert(okbutton);
  193.     vbox->Insert(new VGlue);
  194.  
  195.     Insert(new Frame(vbox, 2));
  196. }
  197.  
  198. // Skew comments/code ratio to work around cpp bug
  199. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  200. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  201. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  202. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  203. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  204.  
  205. // Reconfig pads Messager's shape to make the view look less crowded.
  206.  
  207. void Messager::Reconfig () 
  208. {
  209.     DialogBox::Reconfig();
  210.     Font* font = output->GetFont();
  211.     shape->width += 2 * font->Width("mmmm");
  212.     shape->height += 4 * font->Height();
  213. }
  214.  
  215. // Confirmer creates its button states and initializes its view.
  216.  
  217. Confirmer::Confirmer (Interactor* u, const char* prompt) : (u, prompt) 
  218. {
  219.     yes         = new ButtonState(false);
  220.     no         = new ButtonState(false);
  221.     cancel     = new ButtonState(false);
  222.     yesbutton    = new PushButton(" Yes  ", yes, true);
  223.     nobutton     = new PushButton("  No  ", no, true);
  224.     cancelbutton = new PushButton("Cancel", cancel, true);
  225.     Init();
  226. }
  227.  
  228. // Free storage allocated for the button states.  Yesbutton,
  229. // nobutton, and cancelbutton detach themselves from the button states
  230. // when deleting themselves so we have to delete the states last.
  231.  
  232. Confirmer::~Confirmer () 
  233. {
  234.     delete yes;
  235.     delete no;
  236.     delete cancel;
  237. }
  238.  
  239. // Confirm pops up the Confirmer, lets the user confirm the message or
  240. // not, removes the Confirmer, and returns the confirmation.
  241.  
  242. char Confirmer::Confirm () 
  243. {
  244.     yes->SetValue(false);
  245.     no->SetValue(false);
  246.     cancel->SetValue(false);
  247.  
  248.     PopUp();
  249.  
  250.     int confirmed = false;
  251.     int denied = false;
  252.     int cancelled = false;
  253.     while (!confirmed && !denied && !cancelled) 
  254.     {
  255.     Event e;
  256.     Read(e);
  257.     if (e.eventType == KeyEvent && e.len > 0) 
  258.     {
  259.         switch (e.keystring[0]) 
  260.         {
  261.         case 'y':
  262.         case 'Y':
  263.         yes->SetValue(true);
  264.         break;
  265.         case 'n':
  266.         case 'N':
  267.         no->SetValue(true);
  268.         break;
  269.         case '\r':        // CR
  270.         case '\007':    // ^G
  271.         cancel->SetValue(true);
  272.         break;
  273.         default:
  274.         break;
  275.         }
  276.     }
  277.     else if (e.target == yesbutton || e.target == nobutton ||
  278.          e.target == cancelbutton)
  279.     {
  280.         e.target->Handle(e);
  281.     }
  282.     yes->GetValue(confirmed);
  283.     no->GetValue(denied);
  284.     cancel->GetValue(cancelled);
  285.     }
  286.  
  287.     Disappear();
  288.  
  289.     char answer = 'n';
  290.     answer = confirmed ? 'y' : answer;
  291.     answer = cancelled ? 'c' : answer;
  292.     return answer;
  293. }
  294.  
  295. // Init composes Confirmer's view with boxes, glue, and frames.
  296.  
  297. void Confirmer::Init () 
  298. {
  299.     SetClassName("Confirmer");
  300.  
  301.     HBox* buttons = new HBox;
  302.     buttons->Insert(new HGlue);
  303.     buttons->Insert(yesbutton);
  304.     buttons->Insert(new HGlue);
  305.     buttons->Insert(nobutton);
  306.     buttons->Insert(new HGlue);
  307.     buttons->Insert(cancelbutton);
  308.     buttons->Insert(new HGlue);
  309.  
  310.     VBox* vbox = new VBox;
  311.     vbox->Align(Center);
  312.     vbox->Insert(new VGlue);
  313.     vbox->Insert(warning);
  314.     vbox->Insert(new VGlue);
  315.     vbox->Insert(message);
  316.     vbox->Insert(new VGlue);
  317.     vbox->Insert(buttons);
  318.     vbox->Insert(new VGlue);
  319.  
  320.     Insert(new Frame(vbox, 2));
  321. }
  322.  
  323. // Reconfig pads Confirmer's shape to make the view look less crowded.
  324.  
  325. void Confirmer::Reconfig () 
  326. {
  327.     DialogBox::Reconfig();
  328.     Font* font = output->GetFont();
  329.     shape->width += 4 * font->Width("mmmm");
  330.     shape->height += 4 * font->Height();
  331. }
  332.  
  333. // Namer creates its button states and initializes its view.
  334.  
  335. Namer::Namer (Interactor* u, const char* prompt) : (u, prompt) 
  336. {
  337.     accept = new ButtonState(false);
  338.     cancel = new ButtonState(false);
  339.     acceptbutton = new PushButton("  OK  ", accept, true);
  340.     cancelbutton = new PushButton("Cancel", cancel, true);
  341.     const char* sample = "                                                 ";
  342.     stringeditor = new StringEdit(sample, 3);
  343.     stringeditor->SetString("");
  344.     stringeditor->Extra(80);
  345.     Init();
  346. }
  347.  
  348. // Free storage allocated for the button states.  Acceptbutton
  349. // and cancelbutton detach themselves from the button states when
  350. // deleting themselves so we have to delete the states last of all.
  351.  
  352. Namer::~Namer () 
  353. {
  354.     delete accept;
  355.     delete cancel;
  356. }
  357.  
  358. // Edit pops up the Namer, lets the user edit the given string,
  359. // removes the Namer, and returns the edited string unless the user
  360. // cancelled it.
  361.  
  362. char* Namer::Edit (const char* string) 
  363. {
  364.     accept->SetValue(false);
  365.     cancel->SetValue(false);
  366.     stringeditor->SetString(string);
  367.  
  368.     PopUp();
  369.  
  370.     int accepted = false;
  371.     int cancelled = false;
  372.     while (!accepted && !cancelled) 
  373.     {
  374.     Event e;
  375.     e.eventType = OnEvent;
  376.     stringeditor->Handle(e);
  377.     Read(e);
  378.     if (e.eventType == KeyEvent && e.len > 0) 
  379.     {
  380.         if (e.keystring[0] == '\r') 
  381.         {
  382.         accept->SetValue(true);
  383.         }
  384.         else 
  385.         {
  386.         cancel->SetValue(true);
  387.         }
  388.     }
  389.     else if (e.target == acceptbutton || e.target == cancelbutton) 
  390.     {
  391.         e.target->Handle(e);
  392.     }
  393.  
  394.     accept->GetValue(accepted);
  395.     cancel->GetValue(cancelled);
  396.     }
  397.  
  398.     Disappear();
  399.  
  400.     char* result = nil;
  401.     if (accepted) 
  402.     {
  403.     result = stringeditor->GetString();
  404.     if (result[0] == '\0') 
  405.     {
  406.         delete result;
  407.         result = nil;
  408.     }
  409.     }
  410.  
  411.     return result;
  412. }
  413.  
  414. // Init composes Namer's view with boxes, glue, and frames.
  415.  
  416. void Namer::Init () 
  417. {
  418.     SetClassName("Namer");
  419.  
  420.     HBox* buttons = new HBox;
  421.     buttons->Insert(new HGlue);
  422.     buttons->Insert(acceptbutton);
  423.     buttons->Insert(new HGlue);
  424.     buttons->Insert(cancelbutton);
  425.     buttons->Insert(new HGlue);
  426.  
  427.     VBox* vbox = new VBox;
  428.     vbox->Align(Center);
  429.     vbox->Insert(new VGlue);
  430.     vbox->Insert(warning);
  431.     vbox->Insert(new VGlue);
  432.     vbox->Insert(message);
  433.     vbox->Insert(new VGlue);
  434.     vbox->Insert(new Frame(stringeditor, 1));
  435.     vbox->Insert(new VGlue);
  436.     vbox->Insert(buttons);
  437.     vbox->Insert(new VGlue);
  438.     vbox->Propagate(false);    // so we can reshape stringeditor w/o looping
  439.  
  440.     Insert(new Frame(vbox, 2));
  441. }
  442.  
  443. // Reconfig pads Namer's shape to make the view look less crowded.
  444.  
  445. void Namer::Reconfig () 
  446. {
  447.     DialogBox::Reconfig();
  448.     Shape s = *stringeditor->GetShape();
  449.     s.Rigid();
  450.     stringeditor->Reshape(s);
  451.     Font* font = output->GetFont();
  452.     shape->width += 2 * font->Width("mmmm");
  453.     shape->height += 4 * font->Height();
  454. }
  455.