home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / i / iv26_w_3.zip / EXAMPLES / IDRAW / DIALOGBO.C < prev    next >
C/C++ Source or Header  |  1992-01-29  |  18KB  |  706 lines

  1. /*
  2.  * Copyright (c) 1987, 1988, 1989 Stanford University
  3.  *
  4.  * Permission to use, copy, modify, distribute, and sell this software and its
  5.  * documentation for any purpose is hereby granted without fee, provided
  6.  * that the above copyright notice appear in all copies and that both that
  7.  * copyright notice and this permission notice appear in supporting
  8.  * documentation, and that the name of Stanford not be used in advertising or
  9.  * publicity pertaining to distribution of the software without specific,
  10.  * written prior permission.  Stanford makes no representations about
  11.  * the suitability of this software for any purpose.  It is provided "as is"
  12.  * without express or implied warranty.
  13.  *
  14.  * STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15.  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
  16.  * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  17.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  18.  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  19.  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  20.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  21.  */
  22.  
  23. /*
  24.  * $Header: dialogbox.c,v 1.18 90/01/25 16:29:08 interran Exp $
  25.  * implements class DialogBox and DialogBox subclasses.
  26.  */
  27.  
  28. #include "dialogbox.h"
  29. #include "istring.h"
  30. #include <InterViews/box.h>
  31. #include <InterViews/button.h>
  32. #include <InterViews/canvas.h>
  33. #include <InterViews/event.h>
  34. #include <InterViews/font.h>
  35. #include <InterViews/frame.h>
  36. #include <InterViews/glue.h>
  37. #include <InterViews/message.h>
  38. #include <InterViews/painter.h>
  39. #include <InterViews/sensor.h>
  40. #include <InterViews/shape.h>
  41. #include <InterViews/streditor.h>
  42. #include <InterViews/world.h>
  43. #include <dir.h>
  44.  
  45. /* #include <sys/param.h> */
  46. #define MAXPATHLEN 128
  47.  
  48. /*
  49.  * An IMessage displays its own text, not somebody else's.
  50.  */
  51.  
  52. class IMessage : public Message {
  53. public:
  54.     IMessage(const char* = nil, Alignment a = Center);
  55.     ~IMessage();
  56.  
  57.     void SetText(const char* = nil, const char* = nil);
  58. protected:
  59.     char* buffer;        /* stores own copy of text */
  60. };
  61.  
  62. /*
  63.  * IMessage creates a buffer to store its own copy of the text.
  64.  */
  65.  
  66. IMessage::IMessage (const char* msg, Alignment a) : (nil, a) {
  67.     buffer = strdup(msg ? msg : "");
  68.     text = buffer;
  69. }
  70.  
  71. /*
  72.  * Free storage allocated for the text buffer.
  73.  */
  74.  
  75. IMessage::~IMessage () {
  76.     delete buffer;
  77. }
  78.  
  79. /*
  80.  * SetText stores the new text and changes the IMessage's shape to fit
  81.  * the new text's width.
  82.  */
  83.  
  84. void IMessage::SetText (const char* beg, const char* end) {
  85.     beg = beg ? beg : "";
  86.     end = end ? end : "";
  87.     delete buffer;
  88.     buffer = new char[strlen(beg) + strlen(end) + 1];
  89.     strcpy(buffer, beg);
  90.     strcat(buffer, end);
  91.     text = buffer;
  92.     if (canvas != nil && canvas->Status() == CanvasMapped) {
  93.     Reconfig();
  94.     Parent()->Change(this);
  95.     }
  96. }
  97.  
  98. /*
  99.  * DialogBox creates two IMessages to display a message and a warning
  100.  * and stores its underlying Interactor.  DialogBox won't delete the
  101.  * IMessages so its derived classes can put them in boxes which will
  102.  * delete them when the boxes are deleted.
  103.  */
  104.  
  105. DialogB::DialogB (Interactor* u, const char* msg) {
  106.     SetCanvasType(CanvasSaveUnder); /* speed up expose redrawing if possible */
  107.     input = allEvents;
  108.     input->Reference();
  109.     message = new IMessage(msg);
  110.     warning = new IMessage;
  111.     underlying = u;
  112. }
  113.  
  114. /*
  115.  * SetMessage sets the message's text.
  116.  */
  117.  
  118. void DialogB::SetMessage (const char* beg, const char* end) {
  119.     message->SetText(beg, end);
  120. }
  121.  
  122. /*
  123.  * SetWarning sets the warning's text.
  124.  */
  125.  
  126. void DialogB::SetWarning (const char* beg, const char* end) {
  127.     warning->SetText(beg, end);
  128. }
  129.  
  130. /*
  131.  * SetUnderlying sets the underlying Interactor over which the
  132.  * DialogBox will pop up itself.
  133.  */
  134.  
  135. void DialogB::SetUnderlying (Interactor* u) {
  136.     underlying = u;
  137. }
  138.  
  139. /*
  140.  * PopUp pops up the DialogBox centered over the underlying
  141.  * Interactor's canvas.
  142.  */
  143.  
  144. void DialogB::PopUp () {
  145.     World* world = underlying->GetWorld();
  146.     Coord x, y;
  147.     underlying->Align(Center, 0, 0, x, y);
  148.     underlying->GetRelative(x, y, world);
  149.     world->InsertTransient(this, underlying, x, y, Center);
  150. }
  151.  
  152. /*
  153.  * Disappear removes the DialogBox.  Since the user should see
  154.  * warnings only once, Disappear clears the warning's text so the next
  155.  * PopUp won't display it.
  156.  */
  157.  
  158. void DialogB::Disappear () {
  159.     Parent()->Remove(this);
  160.     SetWarning();
  161.     Sync();
  162. }
  163.  
  164. /*
  165.  * Messager creates its button state and initializes its view.
  166.  */
  167.  
  168. Messager::Messager (Interactor* u, const char* msg) : (u, msg) {
  169.     ok = new ButtonState(0);
  170.     okbutton = new PushButton("  OK  ", ok, true);
  171.     Init();
  172. }
  173.  
  174. /*
  175.  * Free storage allocated for the message's button state.
  176.  */
  177.  
  178. Messager::~Messager () {
  179.     Unref(ok);
  180. }
  181.  
  182. /*
  183.  * Display pops up the Messager and removes it when the user
  184.  * acknowledges the message.
  185.  */
  186.  
  187. void Messager::Display () {
  188.     ok->SetValue(0);
  189.  
  190.     PopUp();
  191.  
  192.     int okay = false;
  193.     while (!okay) {
  194.     Event e;
  195.     Read(e);
  196.     if (e.eventType == KeyEvent && e.len > 0) {
  197.         switch (e.keystring[0]) {
  198.         case '\r':        /* CR */
  199.         case '\007':    /* ^G */
  200.         ok->SetValue(true);
  201.         break;
  202.         default:
  203.         break;
  204.         }
  205.     } else if (e.target == okbutton) {
  206.         e.target->Handle(e);
  207.     }
  208.     ok->GetValue(okay);
  209.     }
  210.  
  211.     Disappear();
  212. }
  213.  
  214. /*
  215.  * Init composes Messager's view with boxes, glue, and frames.
  216.  */
  217.  
  218. void Messager::Init () {
  219.     SetClassName("Messager");
  220.  
  221.     VBox* vbox = new VBox;
  222.     vbox->Align(Center);
  223.     vbox->Insert(new VGlue);
  224.     vbox->Insert(warning);
  225.     vbox->Insert(new VGlue);
  226.     vbox->Insert(message);
  227.     vbox->Insert(new VGlue);
  228.     vbox->Insert(okbutton);
  229.     vbox->Insert(new VGlue);
  230.  
  231.     Insert(new Frame(vbox, 2));
  232. }
  233.  
  234. /*
  235.  * Reconfig pads Messager's shape to make the view look less crowded.
  236.  */
  237.  
  238. void Messager::Reconfig () {
  239.     DialogB::Reconfig();
  240.     Font* font = output->GetFont();
  241.     shape->width += 2 * font->Width("mmmm");
  242.     shape->height += 4 * font->Height();
  243. }
  244.  
  245. /*
  246.  * Confirmer creates its button states and initializes its view.
  247.  */
  248.  
  249. Confirmer::Confirmer (Interactor* u, const char* prompt) : (u, prompt) {
  250.     yes         = new ButtonState(0);
  251.     no         = new ButtonState(0);
  252.     cancel     = new ButtonState(0);
  253.     yesbutton    = new PushButton(" Yes  ", yes, true);
  254.     nobutton     = new PushButton("  No  ", no, true);
  255.     cancelbutton = new PushButton("Cancel", cancel, true);
  256.     Init();
  257. }
  258.  
  259. /*
  260.  * Free storage allocated for the button states.
  261.  */
  262.  
  263. Confirmer::~Confirmer () {
  264.     Unref(yes);
  265.     Unref(no);
  266.     Unref(cancel);
  267. }
  268.  
  269. /*
  270.  * Confirm pops up the Confirmer, lets the user confirm the message or
  271.  * not, removes the Confirmer, and returns the confirmation.
  272.  */
  273.  
  274. char Confirmer::Confirm () {
  275.     yes->SetValue(0);
  276.     no->SetValue(0);
  277.     cancel->SetValue(0);
  278.  
  279.     PopUp();
  280.  
  281.     int confirmed = false;
  282.     int denied = false;
  283.     int cancelled = false;
  284.     while (!confirmed && !denied && !cancelled) {
  285.     Event e;
  286.     Read(e);
  287.     if (e.eventType == KeyEvent && e.len > 0) {
  288.         switch (e.keystring[0]) {
  289.         case 'y':
  290.         case 'Y':
  291.         yes->SetValue(true);
  292.         break;
  293.         case 'n':
  294.         case 'N':
  295.         no->SetValue(true);
  296.         break;
  297.         case '\r':        /* CR */
  298.         case '\007':    /* ^G */
  299.         cancel->SetValue(true);
  300.         break;
  301.         default:
  302.         break;
  303.         }
  304.     } else if (e.target == yesbutton || e.target == nobutton ||
  305.            e.target == cancelbutton)
  306.     {
  307.         e.target->Handle(e);
  308.     }
  309.     yes->GetValue(confirmed);
  310.     no->GetValue(denied);
  311.     cancel->GetValue(cancelled);
  312.     }
  313.  
  314.     Disappear();
  315.  
  316.     char answer = 'n';
  317.     answer = confirmed ? 'y' : answer;
  318.     answer = cancelled ? 'c' : answer;
  319.     return answer;
  320. }
  321.  
  322. /*
  323.  * Init composes Confirmer's view with boxes, glue, and frames.
  324.  */
  325.  
  326. void Confirmer::Init () {
  327.     SetClassName("Confirmer");
  328.  
  329.     HBox* buttons = new HBox;
  330.     buttons->Insert(new HGlue);
  331.     buttons->Insert(yesbutton);
  332.     buttons->Insert(new HGlue);
  333.     buttons->Insert(nobutton);
  334.     buttons->Insert(new HGlue);
  335.     buttons->Insert(cancelbutton);
  336.     buttons->Insert(new HGlue);
  337.  
  338.     VBox* vbox = new VBox;
  339.     vbox->Align(Center);
  340.     vbox->Insert(new VGlue);
  341.     vbox->Insert(warning);
  342.     vbox->Insert(new VGlue);
  343.     vbox->Insert(message);
  344.     vbox->Insert(new VGlue);
  345.     vbox->Insert(buttons);
  346.     vbox->Insert(new VGlue);
  347.  
  348.     Insert(new Frame(vbox, 2));
  349. }
  350.  
  351. /*
  352.  * Reconfig pads Confirmer's shape to make the view look less crowded.
  353.  */
  354.  
  355. void Confirmer::Reconfig () {
  356.     DialogB::Reconfig();
  357.     Font* font = output->GetFont();
  358.     shape->width += 4 * font->Width("mmmm");
  359.     shape->height += 4 * font->Height();
  360. }
  361.  
  362. /*
  363.  * Namer creates its button states and initializes its view.
  364.  */
  365.  
  366. Namer::Namer (Interactor* u, const char* prompt) : (u, prompt) {
  367.     accept = new ButtonState(0);
  368.     cancel = new ButtonState(0);
  369.     acceptbutton = new PushButton("  OK  ", accept, true);
  370.     cancelbutton = new PushButton("Cancel", cancel, true);
  371.     const char* sample = "                                                 ";
  372.     stringeditor = new StringEditor(accept, sample, "\007\015");
  373.     stringeditor->Message("");
  374.     Init();
  375. }
  376.  
  377. /*
  378.  * Free storage allocated for the button states.
  379.  */
  380.  
  381. Namer::~Namer () {
  382.     Unref(accept);
  383.     Unref(cancel);
  384. }
  385.  
  386. /*
  387.  * Edit pops up the Namer, lets the user edit the given string,
  388.  * removes the Namer, and returns the edited string unless the user
  389.  * cancelled it.
  390.  */
  391.  
  392. char* Namer::Edit (const char* string) {
  393.     accept->SetValue(0);
  394.     cancel->SetValue(0);
  395.     if (string != nil) {
  396.     stringeditor->Message(string);
  397.     }
  398.     stringeditor->Select(0, strlen(stringeditor->Text()));
  399.  
  400.     PopUp();
  401.  
  402.     int accepted = false;
  403.     int cancelled = false;
  404.     while (!accepted && !cancelled) {
  405.     stringeditor->Edit();
  406.     accept->GetValue(accepted);
  407.     if (accepted == '\007') {
  408.         accept->SetValue(0);
  409.         cancel->SetValue(true);
  410.     } else if (accepted == '\015') {
  411.         accept->SetValue(true);
  412.         cancel->SetValue(0);
  413.     } else {
  414.         Event e;
  415.         Read(e);
  416.         if (e.target == acceptbutton || e.target == cancelbutton) {
  417.         e.target->Handle(e);
  418.         }
  419.     }
  420.     accept->GetValue(accepted);
  421.     cancel->GetValue(cancelled);
  422.     }
  423.  
  424.     Disappear();
  425.  
  426.     char* result = nil;
  427.     if (accepted) {
  428.     const char* text = stringeditor->Text();
  429.     if (text[0] != '\0') {
  430.         result = strdup(text);
  431.     }
  432.     }
  433.     return result;
  434. }
  435.  
  436. /*
  437.  * Init composes Namer's view with boxes, glue, and frames.
  438.  */
  439.  
  440. void Namer::Init () {
  441.     SetClassName("Namer");
  442.  
  443.     HBox* hboxedit = new HBox;
  444.     hboxedit->Insert(new HGlue(5, 0, 0));
  445.     hboxedit->Insert(stringeditor);
  446.     hboxedit->Insert(new HGlue(5, 0, 0));
  447.  
  448.     VBox* vboxedit = new VBox;
  449.     vboxedit->Insert(new VGlue(2, 0, 0));
  450.     vboxedit->Insert(hboxedit);
  451.     vboxedit->Insert(new VGlue(2, 0, 0));
  452.  
  453.     HBox* buttons = new HBox;
  454.     buttons->Insert(new HGlue);
  455.     buttons->Insert(acceptbutton);
  456.     buttons->Insert(new HGlue);
  457.     buttons->Insert(cancelbutton);
  458.     buttons->Insert(new HGlue);
  459.  
  460.     VBox* vbox = new VBox;
  461.     vbox->Align(Center);
  462.     vbox->Insert(new VGlue);
  463.     vbox->Insert(warning);
  464.     vbox->Insert(new VGlue);
  465.     vbox->Insert(message);
  466.     vbox->Insert(new VGlue);
  467.     vbox->Insert(new Frame(vboxedit, 1));
  468.     vbox->Insert(new VGlue);
  469.     vbox->Insert(buttons);
  470.     vbox->Insert(new VGlue);
  471.     vbox->Propagate(false);    /* for reshaping stringeditor w/o looping */
  472.  
  473.     Insert(new Frame(vbox, 2));
  474. }
  475.  
  476. /*
  477.  * Reconfig pads Namer's shape to make the view look less crowded.
  478.  */
  479.  
  480. void Namer::Reconfig () {
  481.     DialogB::Reconfig();
  482.     Shape s = *stringeditor->GetShape();
  483.     s.Rigid();
  484.     stringeditor->Reshape(s);
  485.     Font* font = output->GetFont();
  486.     shape->width += 2 * font->Width("mmmm");
  487.     shape->height += 4 * font->Height();
  488. }
  489.  
  490. /*
  491.  * NamerNUnit creates its button states and initializes its view.
  492.  */
  493.  
  494. NamerNUnit::NamerNUnit (
  495.     Interactor* u, const char* prompt, const char* label1, const char* label2
  496. ) : (u, prompt) {
  497.     accept = new ButtonState(0);
  498.     cancel = new ButtonState(0);
  499.     unit = new ButtonState((void*)label1);
  500.     acceptbutton = new PushButton("  OK  ", accept, true);
  501.     cancelbutton = new PushButton("Cancel", cancel, true);
  502.     unit1button = new RadioButton(label1, unit, (void*)label1);
  503.     unit2button = new RadioButton(label2, unit, (void*)label2);
  504.     const char* sample = "                         ";
  505.     stringeditor = new StringEditor(accept, sample, "\007\015");
  506.     stringeditor->Message("");
  507.     Init();
  508. }
  509.  
  510. /*
  511.  * Free storage allocated for the button states.
  512.  */
  513.  
  514. NamerNUnit::~NamerNUnit () {
  515.     Unref(accept);
  516.     Unref(cancel);
  517.     Unref(unit);
  518. }
  519.  
  520. /*
  521.  * Edit pops up the NamerNUnit, lets the user edit the given string,
  522.  * removes the NamerNUnit, and returns the edited string with the selected
  523.  * unit appended unless the user cancelled the string.
  524.  */
  525.  
  526. char* NamerNUnit::Edit (const char* string) {
  527.     accept->SetValue(0);
  528.     cancel->SetValue(0);
  529.     if (string != nil) {
  530.     stringeditor->Message(string);
  531.     }
  532.     stringeditor->Select(0, strlen(stringeditor->Text()));
  533.  
  534.     PopUp();
  535.  
  536.     int accepted = false;
  537.     int cancelled = false;
  538.     while (!accepted && !cancelled) {
  539.     stringeditor->Edit();
  540.     accept->GetValue(accepted);
  541.     if (accepted == '\007') {
  542.         accept->SetValue(0);
  543.         cancel->SetValue(true);
  544.     } else if (accepted == '\015') {
  545.         accept->SetValue(true);
  546.         cancel->SetValue(0);
  547.     } else {
  548.         Event e;
  549.         Read(e);
  550.         if (
  551.         e.target == acceptbutton || e.target == cancelbutton ||
  552.         e.target == unit1button || e.target == unit2button
  553.         ) {
  554.         e.target->Handle(e);
  555.         }
  556.     }
  557.     accept->GetValue(accepted);
  558.     cancel->GetValue(cancelled);
  559.     }
  560.  
  561.     Disappear();
  562.  
  563.     char* result = nil;
  564.     if (accepted) {
  565.     const char* text = stringeditor->Text();
  566.     if (text[0] != '\0') {
  567.         void* v;
  568.         unit->GetValue(v);
  569.         const char* u = (char*)v;
  570.         result = new char[strlen(text) + 1 + strlen(u) + 1];
  571.         strcpy(result, text);
  572.         strcat(result, " ");
  573.         strcat(result, u);
  574.     }
  575.     }
  576.     return result;
  577. }
  578.  
  579. /*
  580.  * Init composes NamerNUnit's view with boxes, glue, and frames.
  581.  */
  582.  
  583. void NamerNUnit::Init () {
  584.     SetClassName("NamerNUnit");
  585.  
  586.     HBox* hbox = new HBox;
  587.     hbox->Align(Center);
  588.     hbox->Insert(new HGlue);
  589.     hbox->Insert(new Frame(new MarginFrame(stringeditor, 5, 2)));
  590.     hbox->Insert(new HGlue);
  591.     hbox->Insert(unit1button);
  592.     hbox->Insert(new HGlue);
  593.     hbox->Insert(unit2button);
  594.     hbox->Insert(new HGlue);
  595.  
  596.     HBox* buttons = new HBox;
  597.     buttons->Insert(new HGlue);
  598.     buttons->Insert(acceptbutton);
  599.     buttons->Insert(new HGlue);
  600.     buttons->Insert(cancelbutton);
  601.     buttons->Insert(new HGlue);
  602.  
  603.     VBox* vbox = new VBox;
  604.     vbox->Align(Center);
  605.     vbox->Insert(new VGlue);
  606.     vbox->Insert(warning);
  607.     vbox->Insert(new VGlue);
  608.     vbox->Insert(message);
  609.     vbox->Insert(new VGlue);
  610.     vbox->Insert(hbox);
  611.     vbox->Insert(new VGlue);
  612.     vbox->Insert(buttons);
  613.     vbox->Insert(new VGlue);
  614.     vbox->Propagate(false);    /* for reshaping stringeditor w/o looping */
  615.  
  616.     Insert(new Frame(vbox, 2));
  617. }
  618.  
  619. /*
  620.  * Reconfig pads NamerNUnit's shape to make the view look less crowded.
  621.  */
  622.  
  623. void NamerNUnit::Reconfig () {
  624.     DialogB::Reconfig();
  625.     Shape s = *stringeditor->GetShape();
  626.     s.Rigid();
  627.     stringeditor->Reshape(s);
  628.     Font* font = output->GetFont();
  629.     shape->width += 2 * font->Width("mmmm");
  630.     shape->height += 4 * font->Height();
  631. }
  632.  
  633. /*
  634.  * Helper function for Finder.
  635.  */
  636.  
  637. static const char* abspath (const char* file = nil) {
  638.     const int bufsize = MAXPATHLEN+1;
  639.     static char buf[bufsize];
  640.  
  641. /*
  642.     getcwd(buf, bufsize);
  643.     strcat(buf, "/");
  644.  
  645.     if (file != nil) {
  646.     strcat(buf, file);
  647.     }
  648. */
  649.     getcwd(buf, bufsize);
  650.     if (file != nil) {
  651.         strcat(buf, "\\");
  652.     strcat(buf, file);
  653.     }
  654.     return buf;
  655. }
  656.  
  657. Finder::Finder (
  658.     Interactor* u, const char* t
  659. ) : (new ButtonState, abspath(), 10, 24, Center) {
  660.     underlying = u;
  661.     Init("", t);
  662.     Insert(Interior());
  663. }
  664.  
  665. static const char* ChdirIfNecessary (Finder* finder) {
  666.     static char buf[MAXPATHLEN+1];
  667.     const char* filename = finder->Choice();
  668.     strcpy(buf, filename);
  669.     char* bufptr = strrchr(buf, '\\');
  670.  
  671.     if (bufptr != NULL) {
  672.         *bufptr = '\0';
  673.     if (chdir(buf) == 0) {
  674.             filename = ++bufptr;
  675.             finder->Message(abspath(filename));
  676.         }
  677.     }
  678.     finder->SelectFile();
  679.     return filename;
  680. }
  681.  
  682. const char* Finder::Find () {
  683.     const char* name = nil;
  684.     Event e;
  685.     if (Popup(e)) {
  686.     name = ChdirIfNecessary(this);
  687.     }
  688.     return name;
  689. }
  690.  
  691. Interactor* Finder::Interior () {
  692.     return new Frame(FileChooser::Interior(" Open "), 2);
  693. }
  694.  
  695. boolean Finder::Popup (Event&, boolean) {
  696.     World* world = underlying->GetWorld();
  697.     Coord x, y;
  698.     underlying->Align(Center, 0, 0, x, y);
  699.     underlying->GetRelative(x, y, world);
  700.     world->InsertTransient(this, underlying, x, y, Center);
  701.     boolean accepted = Accept();
  702.     world->Remove(this);
  703.     SetTitle("");
  704.     return accepted;
  705. }
  706.