home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1999 mARCH / PCWK3A99.iso / Linux / DDD331 / DDD-3_1_.000 / DDD-3_1_ / ddd-3.1.1 / ddd / print.C < prev    next >
C/C++ Source or Header  |  1998-11-29  |  27KB  |  1,031 lines

  1. // $Id: print.C,v 1.48 1998/11/29 16:42:53 zeller Exp $ -*- C++ -*-
  2. // Printing dialog
  3.  
  4. // Copyright (C) 1996-1998 Technische Universitaet Braunschweig, Germany.
  5. // Written by Andreas Zeller <zeller@ips.cs.tu-bs.de>.
  6. // 
  7. // This file is part of DDD.
  8. // 
  9. // DDD is free software; you can redistribute it and/or
  10. // modify it under the terms of the GNU General Public
  11. // License as published by the Free Software Foundation; either
  12. // version 2 of the License, or (at your option) any later version.
  13. // 
  14. // DDD is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  17. // See the GNU General Public License for more details.
  18. // 
  19. // You should have received a copy of the GNU General Public
  20. // License along with DDD -- see the file COPYING.
  21. // If not, write to the Free Software Foundation, Inc.,
  22. // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. // 
  24. // DDD is the data display debugger.
  25. // For details, see the DDD World-Wide-Web page, 
  26. // `http://www.cs.tu-bs.de/softech/ddd/',
  27. // or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
  28.  
  29. char print_rcsid[] = 
  30.     "$Id: print.C,v 1.48 1998/11/29 16:42:53 zeller Exp $";
  31.  
  32. #ifdef __GNUG__
  33. #pragma implementation
  34. #endif
  35.  
  36. #include "print.h"
  37.  
  38. #include "AppData.h"
  39. #include "DataDisp.h"
  40. #include "DestroyCB.h"
  41. #include "DispGraph.h"
  42. #include "GraphEdit.h"
  43. #include "Graph.h"
  44. #include "LiterateA.h"
  45. #include "TimeOut.h"
  46. #include "Command.h"
  47. #include "cook.h"
  48. #include "cwd.h"
  49. #include "file.h"
  50. #include "filetype.h"
  51. #include "post.h"
  52. #include "regexps.h"
  53. #include "status.h"
  54. #include "string-fun.h"
  55. #include "verify.h"
  56. #include "wm.h"
  57. #include "charsets.h"
  58. #include "MakeMenu.h"
  59.  
  60. #include "LessTifH.h"
  61.  
  62. #include <ctype.h>
  63. #include <stdio.h>
  64. #include <stdlib.h>
  65. #include <iostream.h>
  66. #include <fstream.h>
  67. #include <string.h>        // strerror()
  68. #include <errno.h>
  69. #include <unistd.h>
  70.  
  71. #include <Xm/Xm.h>
  72. #include <Xm/ToggleB.h>
  73. #include <Xm/RowColumn.h>
  74. #include <Xm/Label.h>
  75. #include <Xm/SelectioB.h>
  76. #include <Xm/MessageB.h>
  77. #include <Xm/Text.h>
  78. #include <Xm/TextF.h>
  79. #include <Xm/PushB.h>
  80. #include <Xm/FileSB.h>
  81.  
  82. #ifndef R_OK
  83. /* 3b2 doesn't define these according to jthomas@nmsu.edu. */
  84. #define R_OK 04
  85. #define W_OK 02
  86. #endif
  87.  
  88.  
  89. //-----------------------------------------------------------------------------
  90. // Printing Dialog
  91. //-----------------------------------------------------------------------------
  92.  
  93. static string msg(string path, bool displays, bool to_file)
  94. {
  95.     string m = "Printing ";
  96.     if (displays)
  97.     m += "graph ";
  98.     else
  99.     m += "plots ";
  100.     if (to_file)
  101.     m += "to ";
  102.     m += quote(path);
  103.     if (!to_file)
  104.     m += " to printer";
  105.  
  106.     return m;
  107. }
  108.  
  109. // Print to FILENAME according to given PrintGC
  110. static int print_to_file(string filename, PrintGC& gc, 
  111.              bool selectedOnly, bool displays)
  112. {
  113.     string path = filename;
  114.     if (!filename.contains('/', 0))
  115.     path.prepend(cwd() + '/');
  116.  
  117.     StatusDelay delay(msg(path, displays, true));
  118.  
  119.     // Get the graph
  120.     Graph *_graph = graphEditGetGraph(data_disp->graph_edit);
  121.     DispGraph *graph = ptr_cast(DispGraph, _graph);
  122.  
  123.     if (graph->firstNode() == 0)
  124.     {
  125.     post_error("No displays to print.", "print_empty_graph_error", 
  126.            data_disp->graph_edit);
  127.     delay.outcome = "failed";
  128.     return -1;
  129.     }
  130.  
  131.     // Get and set the GC
  132.     GraphGC graphGC = graphEditGetGraphGC(data_disp->graph_edit);
  133.     graphGC.printGC = &gc;
  134.     graphGC.printSelectedNodesOnly = selectedOnly;
  135.  
  136.     ofstream os(filename);
  137.     if (os.bad())
  138.     {
  139.     FILE *fp = fopen(filename, "w");
  140.     post_error(string("Cannot open ") 
  141.            + quote(filename) + ": " + strerror(errno), 
  142.            "print_failed_error", data_disp->graph_edit);
  143.     if (fp)
  144.         fclose(fp);
  145.     delay.outcome = strerror(errno);
  146.     return -1;
  147.     }
  148.  
  149.     if (displays)
  150.     {
  151.     // Print displays
  152.     graph->print(os, graphGC);
  153.     }
  154.     else
  155.     {
  156.     // Print plots
  157.     os.close();
  158.     graph->print_plots(filename, graphGC);
  159.     }
  160.  
  161.     return 0;
  162. }
  163.  
  164. static void deletePrintAgent(XtPointer client_data, XtIntervalId *)
  165. {
  166.     // Delete agent after use
  167.     Agent *edit_agent = (Agent *)client_data;
  168.     delete edit_agent;
  169. }
  170.  
  171. static void unlinkPrintFile(XtPointer client_data, XtIntervalId *)
  172. {
  173.     // Delete temp file after use
  174.     string *tempfile = (string *)client_data;
  175.     unlink(*tempfile);
  176.     delete tempfile;
  177. }
  178.  
  179. static string output_buffer;
  180.  
  181. static void printDoneHP(Agent *print_agent, void *client_data, void *)
  182. {
  183.     // Don't get called again
  184.     print_agent->removeAllHandlers(InputEOF);
  185.     print_agent->removeAllHandlers(Died);
  186.  
  187.     // Printing is done: remove temporary file
  188.     XtAppAddTimeOut(XtWidgetToApplicationContext(gdb_w), 0, deletePrintAgent, 
  189.             XtPointer(print_agent));
  190.     XtAppAddTimeOut(XtWidgetToApplicationContext(gdb_w), 0, unlinkPrintFile, 
  191.             XtPointer(client_data));
  192.  
  193.     if (output_buffer != "")
  194.     set_status("");
  195. }
  196.  
  197. static void printOutputHP(Agent *, void *, void *call_data)
  198. {
  199.     DataLength *input = (DataLength *)call_data;
  200.     output_buffer += string(input->data, input->length);
  201.     while (output_buffer.contains('\n'))
  202.     {
  203.     set_status(output_buffer.before('\n'));
  204.     output_buffer = output_buffer.after('\n');
  205.     }
  206.     if (output_buffer != "")
  207.     set_status(output_buffer);
  208. }
  209.  
  210. // Print according to given PrintGC
  211. static int print_to_printer(string command, PrintGC& gc, 
  212.                 bool selectedOnly, bool displays)
  213. {
  214.     string tempfile = tmpnam(0);
  215.     int ret = print_to_file(tempfile, gc, selectedOnly, displays);
  216.     if (ret)
  217.     return ret;
  218.  
  219.     StatusDelay delay(msg(tempfile, displays, false));
  220.  
  221.     command = command + " " + tempfile;
  222.  
  223.     LiterateAgent *print_agent = 
  224.     new LiterateAgent(XtWidgetToApplicationContext(gdb_w), command);
  225.  
  226.     output_buffer = "";
  227.  
  228.     string *sp = new string(tempfile);
  229.  
  230.     print_agent->removeAllHandlers(Died);
  231.     print_agent->addHandler(InputEOF, printDoneHP, (void *)sp);
  232.     print_agent->addHandler(Died,     printDoneHP, (void *)sp);
  233.     print_agent->addHandler(Input, printOutputHP);
  234.     print_agent->addHandler(Error, printOutputHP);
  235.     print_agent->start();
  236.  
  237.     return 0;
  238. }
  239.  
  240. // Local state of print dialog
  241. enum PrintType   { PRINT_POSTSCRIPT, PRINT_FIG };
  242. enum PrintTarget { TARGET_FILE, TARGET_PRINTER };
  243.  
  244. static bool            print_selected_only = false;
  245. static bool            print_displays      = true;
  246. static bool            print_target = TARGET_PRINTER;
  247. static PostScriptPrintGC print_postscript_gc;
  248. static FigPrintGC        print_xfig_gc;
  249. static PrintType       print_type = PRINT_POSTSCRIPT;
  250.  
  251. static Widget          print_dialog = 0;
  252. static Widget          print_command_field   = 0;
  253. static Widget          print_file_name_field = 0;
  254. static Widget            print_file_name_box   = 0;
  255. static Widget          paper_size_dialog = 0;
  256.  
  257. static Widget          a4_paper_size;
  258. static Widget          a3_paper_size;
  259. static Widget          letter_paper_size;
  260. static Widget          legal_paper_size;
  261. static Widget          executive_paper_size;
  262. static Widget          custom_paper_size;
  263.  
  264.  
  265. // Go and print according to local state
  266. void PrintAgainCB(Widget w, XtPointer client_data, XtPointer)
  267. {
  268.     const bool unmanage = ((int)(long)client_data & 1);
  269.     const bool override = ((int)(long)client_data & 2);
  270.  
  271.     switch (print_target)
  272.     {
  273.     case TARGET_PRINTER:
  274.     {
  275.     static string command;
  276.     command = app_data.print_command;
  277.  
  278.     if (print_command_field != 0)
  279.     {
  280.         String c = XmTextFieldGetString(print_command_field);
  281.         command = c;
  282.         XtFree(c);
  283.     }
  284.  
  285.     app_data.print_command = command;
  286.     if (print_to_printer(command, print_postscript_gc, 
  287.                  print_selected_only, print_displays) == 0)
  288.     {
  289.         if (unmanage && print_dialog != 0)
  290.         XtUnmanageChild(print_dialog);
  291.     }
  292.  
  293.     break;
  294.     }
  295.     
  296.     case TARGET_FILE:
  297.     {
  298.     PrintGC *gc_ptr = 0;
  299.     switch (print_type)
  300.     {
  301.     case PRINT_POSTSCRIPT:
  302.         gc_ptr = &print_postscript_gc;
  303.         break;
  304.  
  305.     case PRINT_FIG:
  306.         gc_ptr = &print_xfig_gc;
  307.         break;
  308.     }
  309.     PrintGC& gc = *gc_ptr;
  310.  
  311.     String file = XmTextFieldGetString(print_file_name_field);
  312.     string f = file;
  313.     XtFree(file);
  314.  
  315.     strip_trailing_space(f);
  316.     if (f == "")
  317.         return;
  318.  
  319.     if (access(f, W_OK) || !is_regular_file(f) || override)
  320.     {
  321.         // File does not exist, is special, or override is on
  322.         if (print_to_file(f, gc, print_selected_only, print_displays) == 0)
  323.         {
  324.         if (unmanage && print_dialog != 0)
  325.             XtUnmanageChild(print_dialog);
  326.         }
  327.     }
  328.     else
  329.     {
  330.         // File exists - request confirmation
  331.         static Widget confirm_overwrite_dialog = 0;
  332.         if (confirm_overwrite_dialog)
  333.         DestroyWhenIdle(confirm_overwrite_dialog);
  334.         confirm_overwrite_dialog = 
  335.         verify(XmCreateQuestionDialog(find_shell(w),
  336.                           "confirm_overwrite_dialog", 
  337.                           NULL, 0));
  338.         Delay::register_shell(confirm_overwrite_dialog);
  339.         XtAddCallback(confirm_overwrite_dialog, 
  340.               XmNokCallback, PrintAgainCB, 
  341.               XtPointer((int)(long)client_data | 2));
  342.         XtAddCallback(confirm_overwrite_dialog, 
  343.               XmNhelpCallback, ImmediateHelpCB, 0);
  344.  
  345.         MString question = rm("Overwrite existing file " 
  346.                   + quote(f) + "?");
  347.         XtVaSetValues (confirm_overwrite_dialog, XmNmessageString, 
  348.                question.xmstring(), NULL);
  349.         manage_and_raise(confirm_overwrite_dialog);
  350.     }
  351.  
  352.     break;
  353.     }
  354.     }
  355. }
  356.  
  357. static string suffix(PrintType print_type)
  358. {
  359.     switch (print_type)
  360.     {
  361.     case PRINT_POSTSCRIPT:
  362.     return ".ps";
  363.  
  364.     case PRINT_FIG:
  365.     return ".fig";
  366.     }
  367.  
  368.     return "";
  369. }
  370.  
  371. static void set_print_file_name(const string& name)
  372. {
  373.     XmTextFieldSetString(print_file_name_field, (String)name);
  374.  
  375.     XmTextPosition last_pos = 
  376.     XmTextFieldGetLastPosition(print_file_name_field);
  377.     XmTextFieldSetInsertionPosition(print_file_name_field, last_pos);
  378.     XmTextFieldShowPosition(print_file_name_field, 0);
  379.     XmTextFieldShowPosition(print_file_name_field, last_pos);
  380. }
  381.  
  382. static void SetPrintTypeCB(Widget w, XtPointer client_data, XtPointer)
  383. {
  384.     if (!XmToggleButtonGetState(w))
  385.     return;
  386.  
  387.     string old_suffix = suffix(print_type);
  388.     print_type = PrintType((int)(long)client_data);
  389.     string new_suffix = suffix(print_type);
  390.  
  391.     String file_name_s = XmTextFieldGetString(print_file_name_field);
  392.     string file_name(file_name_s);
  393.     XtFree(file_name_s);
  394.  
  395.     if (file_name.contains(old_suffix, -1))
  396.     {
  397.     int idx = file_name.index(old_suffix, -1);
  398.     file_name = file_name.before(idx) + new_suffix;
  399.  
  400.     set_print_file_name(file_name);
  401.     }
  402. }
  403.  
  404. static void SetSensitiveCB(Widget w, XtPointer client_data, XtPointer)
  405. {
  406.     if (XmToggleButtonGetState(w))
  407.     set_sensitive(Widget(client_data), True);
  408. }
  409.  
  410. static void TakeFocusCB(Widget w, XtPointer client_data, XtPointer)
  411. {
  412.     if (XmToggleButtonGetState(w))
  413.     XmProcessTraversal(Widget(client_data), XmTRAVERSE_CURRENT);
  414. }
  415.  
  416. static void UnsetSensitiveCB(Widget w, XtPointer client_data, XtPointer)
  417. {
  418.     if (XmToggleButtonGetState(w))
  419.     set_sensitive(Widget(client_data), False);
  420. }
  421.  
  422. static void SetPrintDisplaysCB(Widget w, XtPointer, XtPointer)
  423. {
  424.     print_displays = XmToggleButtonGetState(w);
  425. }
  426.  
  427. static void SetPrintSelectedNodesCB(Widget w, XtPointer, XtPointer)
  428. {
  429.     print_selected_only = XmToggleButtonGetState(w);
  430. }
  431.  
  432. static void SetPrintTargetCB(Widget w, XtPointer, XtPointer)
  433. {
  434.     print_target = XmToggleButtonGetState(w) ? TARGET_PRINTER : TARGET_FILE;
  435. }
  436.  
  437. static void set_paper_size_string(string s)
  438. {
  439.     Widget text = XmSelectionBoxGetChild(paper_size_dialog, XmDIALOG_TEXT);
  440.     XmTextSetString(text, s);
  441.  
  442.     static string current_paper_size;
  443.     current_paper_size = s;
  444.     app_data.paper_size = current_paper_size;
  445. }
  446.  
  447. static void SetGCColorCB(Widget w, XtPointer, XtPointer)
  448. {
  449.     print_postscript_gc.color = XmToggleButtonGetState(w);
  450. }
  451.  
  452. static void SetGCA3(Widget w, XtPointer, XtPointer)
  453. {
  454.     if (XmToggleButtonGetState(w))
  455.     {
  456.     PostScriptPrintGC a4;
  457.  
  458.     print_postscript_gc.hsize = a4.vsize;
  459.     print_postscript_gc.vsize = a4.hsize * 2;
  460.     set_paper_size_string("297mm x 420mm");
  461.     }
  462. }
  463.  
  464. static void SetGCA4(Widget w, XtPointer, XtPointer)
  465. {
  466.     if (XmToggleButtonGetState(w))
  467.     {
  468.     PostScriptPrintGC a4;
  469.  
  470.     print_postscript_gc.hsize = a4.hsize;
  471.     print_postscript_gc.vsize = a4.vsize;
  472.     set_paper_size_string("210mm x 297mm");
  473.     }
  474. }
  475.  
  476. static void SetGCLetter(Widget w, XtPointer, XtPointer)
  477. {
  478.     PostScriptPrintGC gc;
  479.  
  480.     if (XmToggleButtonGetState(w))
  481.     {
  482.     print_postscript_gc.hsize = 72 * 8 + 72 / 2 - gc.hoffset * 2;
  483.     print_postscript_gc.vsize = 72 * 11         - gc.voffset * 2;
  484.     set_paper_size_string("8.5in x 11in");
  485.     }
  486. }
  487.  
  488. static void SetGCLegal(Widget w, XtPointer, XtPointer)
  489. {
  490.     PostScriptPrintGC gc;
  491.  
  492.     if (XmToggleButtonGetState(w))
  493.     {
  494.     print_postscript_gc.hsize = 72 * 8 + 72 / 2 - gc.hoffset * 2;
  495.     print_postscript_gc.vsize = 72 * 14         - gc.voffset * 2;
  496.     set_paper_size_string("8.5in x 14in");
  497.     }
  498. }
  499.  
  500. static void SetGCExecutive(Widget w, XtPointer, XtPointer)
  501. {
  502.     PostScriptPrintGC gc;
  503.  
  504.     if (XmToggleButtonGetState(w))
  505.     {
  506.     print_postscript_gc.hsize = 72 * 7 + 72 / 2 - gc.hoffset * 2;
  507.     print_postscript_gc.vsize = 72 * 10         - gc.voffset * 2;
  508.     set_paper_size_string("7.5in x 10in");
  509.     }
  510. }
  511.  
  512. // Convert single unit to points
  513. static int points(string s)
  514. {
  515.     int points = 0;
  516.  
  517.     while (s != "")
  518.     {
  519.     char *start = s;
  520.     char *tailptr;
  521.     double value = strtod(start, &tailptr);
  522.     int value_len = (int)(tailptr - start);
  523.     if (value_len == 0)
  524.     {
  525.         // No size
  526.         return -1;
  527.     }
  528.     s = s.from(value_len);
  529.  
  530.     // Read unit
  531.     string unit = s;
  532.     if (unit.contains(rxdouble))
  533.         unit = unit.before(rxdouble);
  534.  
  535.     strip_space(unit);
  536.     unit.downcase();
  537.  
  538.     if (unit.contains("es", -1))
  539.         unit = unit.before("es");
  540.     if (unit.contains("s", -1))
  541.         unit = unit.before("s");
  542.  
  543.     double factor = 0.0;
  544.     if (unit == "point" || unit == "pt")
  545.         factor = 1.0;
  546.     else if (unit == "inch" || unit == "in" || unit == "\"")
  547.         factor = 72.0;
  548.     else if (unit == "foot" || unit == "feet" 
  549.          || unit == "ft" || unit == "\'")
  550.         factor = 72.0 * 12;
  551.     else if (unit == "yard" || unit == "yd")
  552.         factor = 72.0 * 12 * 3;
  553.     else if (unit == "mile" || unit == "mi")
  554.         factor = 72.0 * 12 * 5280;
  555.     else if (unit == "mm" || unit == "millimeter")
  556.         factor = 72.0 * 1/2.54 * 1/10;
  557.     else if (unit == "cm" || unit == "centimeter")
  558.         factor = 72.0 * 1/2.54;
  559.     else if (unit == "m" || unit == "meter")
  560.         factor = 72.0 * 1/2.54 * 100;
  561.     else if (unit == "km" || unit == "kilometer")
  562.         factor = 72.0 * 1/2.54 * 100000;
  563.     else if (unit == "parsec")                              // ;-)
  564.         factor = 72.0 * 1/2.54 * 100000 * 3.085678e+13;
  565.     else
  566.     {
  567.         // Invalid unit
  568.         return -1;
  569.     }
  570.  
  571.     if (s.contains(rxdouble))
  572.         s = s.from(rxdouble);
  573.     else
  574.         s = "";
  575.  
  576.     if (double(points) + factor * value > double(INT_MAX))
  577.     {
  578.         // Too large
  579.         return -1;
  580.     }
  581.  
  582.     points += int(factor * value);
  583.     }
  584.  
  585.     if (points <= 0)
  586.     {
  587.     // Too small
  588.     return -1;
  589.     }
  590.  
  591.     return points;
  592. }
  593.  
  594. inline bool near(int i, int j)
  595. {
  596.     return abs(i - j) <= 2;
  597. }
  598.  
  599. static void get_paper_size(string s, int& hsize, int& vsize)
  600. {
  601.     char delim = '\0';
  602.  
  603.     if (s.contains('\327'))    // \327 is the times symbol
  604.     delim = '\327';
  605.     else if (s.contains('x'))
  606.     delim = 'x';
  607.     else if (s.contains('X'))
  608.     delim = 'X';
  609.  
  610.     if (delim == '\0')
  611.     {
  612.     // Bad spec
  613.     hsize = -1;
  614.     vsize = -1;
  615.     return;
  616.     }
  617.     
  618.     string s_hsize = s.before(delim);
  619.     string s_vsize = s.after(delim);
  620.  
  621.     hsize = points(s_hsize);
  622.     vsize = points(s_vsize);
  623. }
  624.  
  625. static bool set_paper_size(string s)
  626. {
  627.     int hsize, vsize;
  628.     get_paper_size(s, hsize, vsize);
  629.  
  630.     if (hsize <= 0 || vsize <= 0)
  631.     return false;        // Error
  632.  
  633.     PostScriptPrintGC gc;
  634.  
  635.     print_postscript_gc.hsize = hsize - gc.hoffset * 2;
  636.     print_postscript_gc.vsize = vsize - gc.voffset * 2;
  637.  
  638.     if (near(hsize, 594) && near(vsize, 840))
  639.     XmToggleButtonSetState(a4_paper_size, True, True);
  640.     else if (near(hsize, 840) && near(vsize, 1188))
  641.     XmToggleButtonSetState(a3_paper_size, True, True);
  642.     else if (hsize == 72 * 8 + 72 / 2 && vsize == 72 * 11)
  643.     XmToggleButtonSetState(letter_paper_size, True, True);
  644.     else if (hsize == 72 * 8 + 72 / 2 && vsize == 72 * 14)
  645.     XmToggleButtonSetState(legal_paper_size, True, True);
  646.     else if (hsize == 72 * 7 + 72 / 2 && vsize == 72 * 10)
  647.     XmToggleButtonSetState(executive_paper_size, True, True);
  648.     else
  649.     {
  650.     XmToggleButtonSetState(a4_paper_size, False, False);
  651.     XmToggleButtonSetState(a3_paper_size, False, False);
  652.     XmToggleButtonSetState(letter_paper_size, False, False);
  653.     XmToggleButtonSetState(legal_paper_size, False, False);
  654.     XmToggleButtonSetState(executive_paper_size, False, False);
  655.     XmToggleButtonSetState(custom_paper_size, True, False);
  656.     }
  657.  
  658.     set_paper_size_string(s);
  659.  
  660.     return true;
  661. }
  662.  
  663. static void SetPaperSizeCB(Widget w, XtPointer, XtPointer call_data)
  664. {
  665.     XmFileSelectionBoxCallbackStruct *cbs =
  666.     (XmFileSelectionBoxCallbackStruct *)call_data;
  667.  
  668.     string s = "";
  669.     char *value = 0;
  670.  
  671.     if (XmStringGetLtoR(cbs->value, MSTRING_DEFAULT_CHARSET, &value)
  672.     && value != 0)
  673.     {
  674.     s = value;
  675.     XtFree(value);
  676.     }
  677.  
  678.     int ok = true;
  679.     if (s != "")
  680.     ok = set_paper_size(s);
  681.  
  682.     if (ok)
  683.     XtUnmanageChild(w);
  684. }
  685.  
  686. static void CheckPaperSizeCB(Widget text, XtPointer client_data, XtPointer)
  687. {
  688.     Widget ok_button = Widget(client_data);
  689.     String value;
  690.     XtVaGetValues(text, XmNvalue, &value, NULL);
  691.     string size(value);
  692.     XtFree(value);
  693.  
  694.     int hsize, vsize;
  695.     get_paper_size(size, hsize, vsize);
  696.  
  697.     set_sensitive(ok_button, hsize >= 0 && vsize >= 0);
  698. }
  699.  
  700. static void ResetPaperSizeCB(Widget w, XtPointer, XtPointer)
  701. {
  702.     set_paper_size(app_data.paper_size);
  703.     XtUnmanageChild(w);
  704. }
  705.  
  706. static void SetGCCustom(Widget w, XtPointer, XtPointer)
  707. {
  708.     if (!XmToggleButtonGetState(w))
  709.     return;
  710.  
  711.     manage_and_raise(paper_size_dialog);
  712. }
  713.  
  714. static void SetGCOrientation(Widget w, XtPointer, XtPointer)
  715. {
  716.     if (XmToggleButtonGetState(w))
  717.     print_postscript_gc.orientation = PostScriptPrintGC::PORTRAIT;
  718.     else
  719.     print_postscript_gc.orientation = PostScriptPrintGC::LANDSCAPE;
  720. }
  721.  
  722. static void NopCB(Widget, XtPointer, XtPointer)
  723. {}
  724.  
  725. static void SetPrintFileNameCB(Widget w,
  726.                    XtPointer client_data, 
  727.                    XtPointer call_data)
  728. {
  729.     string target = get_file(w, client_data, call_data);
  730.     if (target != "")
  731.     {
  732.     set_print_file_name(target);
  733.     XtUnmanageChild(w);
  734.     }
  735. }
  736.  
  737. static void BrowseNameCB(Widget w, XtPointer, XtPointer)
  738. {
  739.     Delay delay;
  740.  
  741.     static Widget dialog = 0;
  742.  
  743.     static MString pattern;
  744.  
  745.     String file = XmTextFieldGetString(print_file_name_field);
  746.     string f = file;
  747.     XtFree(file);
  748.  
  749.     if (f.contains('.'))
  750.     pattern = "*" + f.from('.', -1);
  751.     else
  752.     {
  753.     switch (print_type)
  754.     {
  755.     case PRINT_POSTSCRIPT:
  756.         pattern = "*.ps";
  757.         break;
  758.  
  759.     case PRINT_FIG:
  760.         pattern = "*.fig";
  761.         break;
  762.     }
  763.     }
  764.  
  765.     Arg args[10];
  766.     Cardinal arg = 0;
  767.  
  768.     if (dialog == 0)
  769.     {
  770.     XtSetArg(args[arg], XmNpattern, pattern.xmstring()); arg++;
  771.     dialog = 
  772.         verify(XmCreateFileSelectionDialog(find_shell(w), 
  773.                            "browse_print", args, arg));
  774.  
  775.     Delay::register_shell(dialog);
  776.     XtAddCallback(dialog, XmNokCallback, SetPrintFileNameCB, 0);
  777.     XtAddCallback(dialog, XmNcancelCallback, UnmanageThisCB, 
  778.               XtPointer(dialog));
  779.     XtAddCallback(dialog, XmNhelpCallback, ImmediateHelpCB, XtPointer(0));
  780.     }
  781.     else
  782.     {
  783.     XtSetArg(args[arg], XmNpattern, pattern.xmstring()); arg++;
  784.     XtSetValues(dialog, args, arg);
  785.     }
  786.  
  787.     manage_and_raise(dialog);
  788. }
  789.  
  790. static void PrintCB(Widget parent, bool displays)
  791. {
  792.     print_displays = displays;
  793.  
  794.     static Widget print_displays_w;
  795.     static Widget print_plots_w;
  796.     static Widget print_selected_w;
  797.  
  798.     if (print_dialog != 0)
  799.     {
  800.     // Dialog already created -- pop it up again
  801.     XmToggleButtonSetState(print_plots_w, !displays, True);
  802.     XmToggleButtonSetState(print_displays_w, displays, True);
  803.     XmToggleButtonSetState(print_selected_w, 
  804.                    data_disp->have_selection(), True);
  805.     manage_and_raise(print_dialog);
  806.     return;
  807.     }
  808.  
  809.     Arg args[10];
  810.     Cardinal arg = 0;
  811.     XtSetArg(args[arg], XmNautoUnmanage, False); arg++;
  812.     print_dialog = 
  813.     verify(XmCreatePromptDialog(find_shell(parent), "print", args, arg));
  814.     Delay::register_shell(print_dialog);
  815.  
  816.     if (lesstif_version <= 79)
  817.     XtUnmanageChild(XmSelectionBoxGetChild(print_dialog,
  818.                            XmDIALOG_APPLY_BUTTON));
  819.  
  820.     XtAddCallback(print_dialog, XmNokCallback,
  821.            PrintAgainCB, XtPointer(1));
  822.     XtAddCallback(print_dialog, XmNapplyCallback,
  823.           PrintAgainCB, XtPointer(0));
  824.     XtAddCallback(print_dialog, XmNcancelCallback, 
  825.           UnmanageThisCB, XtPointer(print_dialog));
  826.     XtAddCallback(print_dialog, XmNhelpCallback,
  827.           ImmediateHelpCB, XtPointer(0));
  828.  
  829.     // Remove old prompt
  830.     XtUnmanageChild(XmSelectionBoxGetChild(print_dialog, XmDIALOG_TEXT));
  831.     XtUnmanageChild(XmSelectionBoxGetChild(print_dialog, 
  832.                        XmDIALOG_SELECTION_LABEL));
  833.  
  834.     // Create menu
  835.     static Widget print_to_printer_w;
  836.     static Widget print_to_file_w;
  837.     static MMDesc print_to_menu[] = 
  838.     {
  839.     {"printer", MMToggle, 
  840.      { SetPrintTargetCB, 0 }, NULL, &print_to_printer_w, 0, 0},
  841.     {"file",    MMToggle, { NopCB, 0 }, NULL, &print_to_file_w, 0, 0 },
  842.     MMEnd
  843.     };
  844.  
  845.     static Widget postscript_w;
  846.     static Widget fig_w;
  847.     static MMDesc type2_menu[] = 
  848.     {
  849.     {"postscript", MMToggle, 
  850.      { SetPrintTypeCB, XtPointer(PRINT_POSTSCRIPT) }, 
  851.      0, &postscript_w, 0, 0 },
  852.     {"xfig",       MMToggle,
  853.       { SetPrintTypeCB, XtPointer(PRINT_FIG) }, 0, &fig_w, 0, 0},
  854.     MMEnd
  855.     };
  856.  
  857.     static Widget print_color_w;
  858.     static MMDesc type_menu[] = 
  859.     {
  860.     {"type2",    MMRadioPanel | MMUnmanagedLabel, 
  861.      MMNoCB, type2_menu, 0, 0, 0 },
  862.     {"color",    MMToggle, { SetGCColorCB, 0 }, 
  863.                  NULL, &print_color_w, 0, 0 },
  864.     MMEnd
  865.     };
  866.  
  867.     static MMDesc what2_menu[] = 
  868.     {
  869.     {"displays", MMToggle, { SetPrintDisplaysCB, 0 }, NULL, 
  870.      &print_displays_w, 0, 0 },
  871.     {"plots",    MMToggle, { NopCB, 0 }, NULL, &print_plots_w, 0, 0 },
  872.     MMEnd
  873.     };
  874.  
  875.     static MMDesc what_menu[] = 
  876.     {
  877.     {"what2",    MMRadioPanel | MMUnmanagedLabel, 
  878.      MMNoCB, what2_menu, 0, 0, 0 },
  879.     {"selected", MMToggle, { SetPrintSelectedNodesCB, 0 }, 
  880.                  NULL, &print_selected_w, 0, 0 },
  881.     MMEnd
  882.     };
  883.  
  884.     static Widget print_portrait_w;
  885.     static MMDesc orientation_menu[] = 
  886.     {
  887.     {"portrait",  MMToggle, 
  888.      { SetGCOrientation, 0 }, NULL, &print_portrait_w, 0, 0},
  889.     {"landscape", MMToggle, { NopCB, 0 }, 0, 0, 0, 0},
  890.     MMEnd
  891.     };
  892.  
  893.     static MMDesc paper_menu[] = 
  894.     {
  895.     {"a4",        MMToggle, 
  896.      {SetGCA4, 0},        NULL, &a4_paper_size, 0, 0},
  897.     {"a3",        MMToggle, 
  898.      {SetGCA3, 0},        NULL, &a3_paper_size, 0, 0},
  899.     {"letter",    MMToggle, 
  900.      {SetGCLetter, 0},    NULL, &letter_paper_size, 0, 0},
  901.     {"legal",     MMToggle, 
  902.      {SetGCLegal, 0},     NULL, &legal_paper_size, 0, 0},
  903.     {"executive", MMToggle, 
  904.      {SetGCExecutive, 0}, NULL, &executive_paper_size, 0, 0},
  905.     {"custom",    MMToggle, 
  906.      {SetGCCustom, 0},    NULL, &custom_paper_size, 0, 0},
  907.     MMEnd
  908.     };
  909.  
  910.     static MMDesc name_menu[] = 
  911.     {
  912.     {"name",     MMTextField | MMUnmanagedLabel, MMNoCB, 
  913.      0, &print_file_name_field, 0, 0},
  914.     {"browse",      MMPush, { BrowseNameCB, 0 }, 0, 0, 0, 0 },
  915.     MMEnd
  916.     };
  917.  
  918.     static MMDesc menu[] =
  919.     {
  920.     {"to",          MMRadioPanel, MMNoCB, print_to_menu, 0, 0, 0 },
  921.     {"command",     MMTextField,  MMNoCB, 0, &print_command_field, 0, 0 },
  922.     {"name",     MMPanel,      MMNoCB, name_menu, 
  923.      &print_file_name_box, 0, 0},
  924.     MMSep,
  925.     {"type",     MMPanel,      MMNoCB, type_menu, 0, 0, 0 },
  926.     {"what",        MMPanel,      MMNoCB, what_menu, 0, 0, 0 },
  927.     {"orientation", MMRadioPanel, MMNoCB, orientation_menu, 0, 0, 0 },
  928.     {"size",        MMRadioPanel, MMNoCB, paper_menu, 0, 0, 0 },
  929.     MMEnd
  930.     };
  931.  
  932.     Widget panel = MMcreatePanel(print_dialog, "options", menu);
  933.     (void) panel;        // Use it
  934.     MMadjustPanel(menu);
  935.  
  936.     // Add callbacks
  937.     MMaddCallbacks(menu);
  938.  
  939.     XtAddCallback(print_to_printer_w, XmNvalueChangedCallback,   
  940.           SetSensitiveCB,   XtPointer(print_command_field));
  941.     XtAddCallback(print_to_printer_w, XmNvalueChangedCallback,   
  942.           SetSensitiveCB,   XtPointer(menu[1].label));
  943.  
  944.     XtAddCallback(print_to_printer_w, XmNvalueChangedCallback,
  945.           UnsetSensitiveCB, XtPointer(print_file_name_box));
  946.     XtAddCallback(print_to_printer_w, XmNvalueChangedCallback,
  947.           UnsetSensitiveCB, XtPointer(menu[2].label));
  948.     XtAddCallback(print_to_printer_w, XmNvalueChangedCallback,
  949.           UnsetSensitiveCB, XtPointer(postscript_w));
  950.     XtAddCallback(print_to_printer_w, XmNvalueChangedCallback,
  951.           UnsetSensitiveCB, XtPointer(fig_w));
  952.  
  953.     XtAddCallback(print_to_printer_w, XmNvalueChangedCallback,
  954.           TakeFocusCB,      XtPointer(print_command_field));
  955.  
  956.     XtAddCallback(print_to_file_w, XmNvalueChangedCallback,   
  957.           UnsetSensitiveCB, XtPointer(print_command_field));
  958.     XtAddCallback(print_to_file_w, XmNvalueChangedCallback,   
  959.           UnsetSensitiveCB, XtPointer(menu[1].label));
  960.  
  961.     XtAddCallback(print_to_file_w, XmNvalueChangedCallback,   
  962.           SetSensitiveCB,   XtPointer(print_file_name_box));
  963.     XtAddCallback(print_to_file_w, XmNvalueChangedCallback,
  964.           SetSensitiveCB,   XtPointer(menu[2].label));
  965.     XtAddCallback(print_to_file_w, XmNvalueChangedCallback,   
  966.           SetSensitiveCB,   XtPointer(postscript_w));
  967.     XtAddCallback(print_to_file_w, XmNvalueChangedCallback,   
  968.           SetSensitiveCB,   XtPointer(fig_w));
  969.  
  970.     XtAddCallback(print_to_file_w, XmNvalueChangedCallback,
  971.           TakeFocusCB,      XtPointer(print_file_name_field));
  972.  
  973.  
  974.     // Create size dialog
  975.     arg = 0;
  976.     XtSetArg(args[arg], XmNautoUnmanage, False); arg++;
  977.     paper_size_dialog = 
  978.     verify(XmCreatePromptDialog(find_shell(parent), "paper_size_dialog", 
  979.                     args, arg));
  980.     Delay::register_shell(paper_size_dialog);
  981.  
  982.     if (lesstif_version <= 79)
  983.     XtUnmanageChild(XmSelectionBoxGetChild(paper_size_dialog,
  984.                            XmDIALOG_APPLY_BUTTON));
  985.  
  986.     XtAddCallback(paper_size_dialog, XmNokCallback,
  987.           SetPaperSizeCB, XtPointer(0));
  988.     XtAddCallback(paper_size_dialog, XmNcancelCallback, 
  989.           ResetPaperSizeCB, XtPointer(0));
  990.     XtAddCallback(paper_size_dialog, XmNhelpCallback,   
  991.           ImmediateHelpCB, XtPointer(0));
  992.  
  993.     Widget size = XmSelectionBoxGetChild(paper_size_dialog,
  994.                      XmDIALOG_TEXT);
  995.     Widget ok_button = XmSelectionBoxGetChild(paper_size_dialog, 
  996.                           XmDIALOG_OK_BUTTON);
  997.     XtAddCallback(size, XmNvalueChangedCallback, 
  998.           CheckPaperSizeCB, XtPointer(ok_button));
  999.  
  1000.     // Set initial state
  1001.     XmToggleButtonSetState(print_to_printer_w, True, True);
  1002.     XmToggleButtonSetState(postscript_w, True, True);
  1003.     XmToggleButtonSetState(print_color_w, False, True);
  1004.     XmToggleButtonSetState(print_selected_w, False, True);
  1005.     XmToggleButtonSetState(print_portrait_w, True, True);
  1006.     XmToggleButtonSetState(print_plots_w, !displays, True);
  1007.     XmToggleButtonSetState(print_displays_w, displays, True);
  1008.     XmToggleButtonSetState(print_selected_w, 
  1009.                data_disp->have_selection(), True);
  1010.  
  1011.     bool ok = set_paper_size(app_data.paper_size);
  1012.     if (!ok)
  1013.     XmToggleButtonSetState(a4_paper_size, True, True);
  1014.  
  1015.     string command = string(app_data.print_command) + " ";
  1016.     XmTextFieldSetString(print_command_field, command);
  1017.  
  1018.     // Gofer it!
  1019.     manage_and_raise(print_dialog);
  1020. }
  1021.  
  1022. void PrintGraphCB(Widget w, XtPointer, XtPointer)
  1023. {
  1024.     PrintCB(w, true);
  1025. }
  1026.  
  1027. void PrintPlotCB(Widget w, XtPointer, XtPointer)
  1028. {
  1029.     PrintCB(w, false);
  1030. }
  1031.