pcb 4.1.1
An interactive printed circuit board layout editor.

dialogs.c

Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include "config.h"
00003 #endif
00004 
00005 #include <stdio.h>
00006 #include <stdarg.h>
00007 #include <stdlib.h>
00008 #include <string.h>
00009 
00010 #include "xincludes.h"
00011 
00012 #include "compat.h"
00013 #include "global.h"
00014 #include "data.h"
00015 #include "crosshair.h"
00016 #include "misc.h"
00017 #include "pcb-printf.h"
00018 
00019 #include "hid.h"
00020 #include "../hidint.h"
00021 #include "lesstif.h"
00022 
00023 #ifdef HAVE_LIBDMALLOC
00024 #include <dmalloc.h>
00025 #endif
00026 
00027 #define CRASH fprintf(stderr, "HID error: pcb called unimplemented GUI function %s\n", __FUNCTION__), abort()
00028 
00029 static Arg args[30];
00030 static int n;
00031 #define stdarg(t,v) XtSetArg(args[n], t, v); n++
00032 
00033 static int ok;
00034 
00035 #define TOP_SIDE_NAME "(top)"
00036 #define BOTTOM_SIDE_NAME "(bottom)"
00037 
00038 /* ------------------------------------------------------------ */
00039 
00040 static void
00041 dialog_callback (Widget w, void *v, void *cbs)
00042 {
00043   ok = (int) (size_t) v;
00044 }
00045 
00046 static int
00047 wait_for_dialog (Widget w)
00048 {
00049   ok = -1;
00050   XtManageChild (w);
00051   while (ok == -1 && XtIsManaged (w))
00052     {
00053       XEvent e;
00054       XtAppNextEvent (app_context, &e);
00055       XtDispatchEvent (&e);
00056     }
00057   XtUnmanageChild (w);
00058   return ok;
00059 }
00060 
00061 /* ------------------------------------------------------------ */
00062 
00063 static Widget fsb = 0;
00064 static XmString xms_pcb, xms_net, xms_vend, xms_all, xms_load, xms_loadv,
00065   xms_save, xms_fp;
00066 
00067 static void
00068 setup_fsb_dialog ()
00069 {
00070   if (fsb)
00071     return;
00072 
00073   xms_pcb = XmStringCreatePCB ("*.pcb");
00074   xms_fp = XmStringCreatePCB ("*.fp");
00075   xms_net = XmStringCreatePCB ("*.net");
00076   xms_vend = XmStringCreatePCB ("*.vend");
00077   xms_all = XmStringCreatePCB ("*");
00078   xms_load = XmStringCreatePCB ("Load From");
00079   xms_loadv = XmStringCreatePCB ("Load Vendor");
00080   xms_save = XmStringCreatePCB ("Save As");
00081 
00082   n = 0;
00083   fsb = XmCreateFileSelectionDialog (mainwind, "file", args, n);
00084 
00085   XtAddCallback (fsb, XmNokCallback, (XtCallbackProc) dialog_callback,
00086                  (XtPointer) 1);
00087   XtAddCallback (fsb, XmNcancelCallback, (XtCallbackProc) dialog_callback,
00088                  (XtPointer) 0);
00089 }
00090 
00091 static const char load_syntax[] =
00092 "Load()\n"
00093 "Load(Layout|LayoutToBuffer|ElementToBuffer|Netlist|Revert)";
00094 
00095 static const char load_help[] =
00096 "Load layout data from a user-selected file.";
00097 
00098 /* %start-doc actions Load
00099 
00100 This action is a GUI front-end to the core's @code{LoadFrom} action
00101 (@pxref{LoadFrom Action}).  If you happen to pass a filename, like
00102 @code{LoadFrom}, then @code{LoadFrom} is called directly.  Else, the
00103 user is prompted for a filename to load, and then @code{LoadFrom} is
00104 called with that filename.
00105 
00106 %end-doc */
00107 
00108 static int
00109 Load (int argc, char **argv, Coord x, Coord y)
00110 {
00111   const char *function;
00112   char *name;
00113   XmString xmname, pattern;
00114 
00115   if (argc > 1)
00116     return hid_actionv ("LoadFrom", argc, argv);
00117 
00118   function = argc ? argv[0] : "Layout";
00119 
00120   setup_fsb_dialog ();
00121 
00122   if (strcasecmp (function, "Netlist") == 0)
00123     pattern = xms_net;
00124   else if (strcasecmp (function, "ElementToBuffer") == 0)
00125     pattern = xms_fp;
00126   else
00127     pattern = xms_pcb;
00128 
00129   n = 0;
00130   stdarg (XmNtitle, "Load From");
00131   XtSetValues (XtParent (fsb), args, n);
00132 
00133   n = 0;
00134   stdarg (XmNpattern, pattern);
00135   stdarg (XmNmustMatch, True);
00136   stdarg (XmNselectionLabelString, xms_load);
00137   XtSetValues (fsb, args, n);
00138 
00139   if (!wait_for_dialog (fsb))
00140     return 1;
00141 
00142   n = 0;
00143   stdarg (XmNdirSpec, &xmname);
00144   XtGetValues (fsb, args, n);
00145 
00146   XmStringGetLtoR (xmname, XmFONTLIST_DEFAULT_TAG, &name);
00147 
00148   hid_actionl ("LoadFrom", function, name, NULL);
00149 
00150   XtFree (name);
00151 
00152   return 0;
00153 }
00154 
00155 static const char loadvendor_syntax[] =
00156 "LoadVendor()";
00157 
00158 static const char loadvendor_help[] =
00159 "Loads a user-selected vendor resource file.";
00160 
00161 /* %start-doc actions LoadVendor
00162 
00163 The user is prompted for a file to load, and then
00164 @code{LoadVendorFrom} is called (@pxref{LoadVendorFrom Action}) to
00165 load that vendor file.
00166 
00167 %end-doc */
00168 
00169 static int
00170 LoadVendor (int argc, char **argv, Coord x, Coord y)
00171 {
00172   char *name;
00173   XmString xmname, pattern;
00174 
00175   if (argc > 0)
00176     return hid_actionv ("LoadVendorFrom", argc, argv);
00177 
00178   setup_fsb_dialog ();
00179 
00180   pattern = xms_vend;
00181 
00182   n = 0;
00183   stdarg (XmNtitle, "Load Vendor");
00184   XtSetValues (XtParent (fsb), args, n);
00185 
00186   n = 0;
00187   stdarg (XmNpattern, pattern);
00188   stdarg (XmNmustMatch, True);
00189   stdarg (XmNselectionLabelString, xms_loadv);
00190   XtSetValues (fsb, args, n);
00191 
00192   if (!wait_for_dialog (fsb))
00193     return 1;
00194 
00195   n = 0;
00196   stdarg (XmNdirSpec, &xmname);
00197   XtGetValues (fsb, args, n);
00198 
00199   XmStringGetLtoR (xmname, XmFONTLIST_DEFAULT_TAG, &name);
00200 
00201   hid_actionl ("LoadVendorFrom", name, NULL);
00202 
00203   XtFree (name);
00204 
00205   return 0;
00206 }
00207 
00208 static const char save_syntax[] =
00209 "Save()\n"
00210 "Save(Layout|LayoutAs)\n"
00211 "Save(AllConnections|AllUnusedPins|ElementConnections)\n"
00212 "Save(PasteBuffer)";
00213 
00214 static const char save_help[] =
00215 "Save layout data to a user-selected file.";
00216 
00217 /* %start-doc actions Save
00218 
00219 This action is a GUI front-end to the core's @code{SaveTo} action
00220 (@pxref{SaveTo Action}).  If you happen to pass a filename, like
00221 @code{SaveTo}, then @code{SaveTo} is called directly.  Else, the
00222 user is prompted for a filename to save, and then @code{SaveTo} is
00223 called with that filename.
00224 
00225 %end-doc */
00226 
00227 static int
00228 Save (int argc, char **argv, Coord x, Coord y)
00229 {
00230   const char *function;
00231   char *name;
00232   XmString xmname, pattern;
00233 
00234   if (argc > 1)
00235     hid_actionv ("SaveTo", argc, argv);
00236 
00237   function = argc ? argv[0] : "Layout";
00238   
00239   if (strcasecmp (function, "Layout") == 0)
00240     if (PCB->Filename)
00241       return hid_actionl ("SaveTo", "Layout", PCB->Filename, NULL);
00242 
00243   setup_fsb_dialog ();
00244 
00245   pattern = xms_pcb;
00246 
00247   XtManageChild (fsb);
00248 
00249   n = 0;
00250   stdarg (XmNtitle, "Save As");
00251   XtSetValues (XtParent (fsb), args, n);
00252 
00253   n = 0;
00254   stdarg (XmNpattern, pattern);
00255   stdarg (XmNmustMatch, False);
00256   stdarg (XmNselectionLabelString, xms_save);
00257   XtSetValues (fsb, args, n);
00258 
00259   if (!wait_for_dialog (fsb))
00260     return 1;
00261 
00262   n = 0;
00263   stdarg (XmNdirSpec, &xmname);
00264   XtGetValues (fsb, args, n);
00265 
00266   XmStringGetLtoR (xmname, XmFONTLIST_DEFAULT_TAG, &name);
00267 
00268   if (strcasecmp (function, "PasteBuffer") == 0)
00269     hid_actionl ("PasteBuffer", "Save", name, NULL);
00270   else
00271     {
00272       /* 
00273        * if we got this far and the function is Layout, then
00274        * we really needed it to be a LayoutAs.  Otherwise 
00275        * ActionSaveTo() will ignore the new file name we
00276        * just obtained.
00277        */
00278       if (strcasecmp (function, "Layout") == 0)
00279         hid_actionl ("SaveTo", "LayoutAs", name, NULL);
00280       else
00281         hid_actionl ("SaveTo", function, name, NULL);
00282     }
00283   XtFree (name);
00284 
00285   return 0;
00286 }
00287 
00288 /* ------------------------------------------------------------ */
00289 
00290 static Widget log_form, log_text;
00291 static int log_size = 0;
00292 static int pending_newline = 0;
00293 
00294 static void
00295 log_clear (Widget w, void *up, void *cbp)
00296 {
00297   XmTextSetString (log_text, "");
00298   log_size = 0;
00299   pending_newline = 0;
00300 }
00301 
00302 static void
00303 log_dismiss (Widget w, void *up, void *cbp)
00304 {
00305   XtUnmanageChild (log_form);
00306 }
00307 
00308 void
00309 lesstif_logv (const char *fmt, va_list ap)
00310 {
00311   gchar *buf, *scan;
00312   if (!mainwind)
00313     {
00314       vprintf (fmt, ap);
00315       return;
00316     }
00317   if (!log_form)
00318     {
00319       Widget clear_button, dismiss_button;
00320 
00321       n = 0;
00322       stdarg (XmNautoUnmanage, False);
00323       stdarg (XmNwidth, 600);
00324       stdarg (XmNheight, 200);
00325       stdarg (XmNtitle, "PCB Log");
00326       log_form = XmCreateFormDialog (mainwind, "log", args, n);
00327 
00328       n = 0;
00329       stdarg (XmNrightAttachment, XmATTACH_FORM);
00330       stdarg (XmNbottomAttachment, XmATTACH_FORM);
00331       clear_button = XmCreatePushButton (log_form, "clear", args, n);
00332       XtManageChild (clear_button);
00333       XtAddCallback (clear_button, XmNactivateCallback,
00334                      (XtCallbackProc) log_clear, 0);
00335 
00336       n = 0;
00337       stdarg (XmNrightAttachment, XmATTACH_WIDGET);
00338       stdarg (XmNrightWidget, clear_button);
00339       stdarg (XmNbottomAttachment, XmATTACH_FORM);
00340       dismiss_button = XmCreatePushButton (log_form, "dismiss", args, n);
00341       XtManageChild (dismiss_button);
00342       XtAddCallback (dismiss_button, XmNactivateCallback,
00343                      (XtCallbackProc) log_dismiss, 0);
00344 
00345       n = 0;
00346       stdarg (XmNeditable, False);
00347       stdarg (XmNeditMode, XmMULTI_LINE_EDIT);
00348       stdarg (XmNcursorPositionVisible, True);
00349       stdarg (XmNtopAttachment, XmATTACH_FORM);
00350       stdarg (XmNleftAttachment, XmATTACH_FORM);
00351       stdarg (XmNrightAttachment, XmATTACH_FORM);
00352       stdarg (XmNbottomAttachment, XmATTACH_WIDGET);
00353       stdarg (XmNbottomWidget, clear_button);
00354       log_text = XmCreateScrolledText (log_form, "text", args, n);
00355       XtManageChild (log_text);
00356 
00357       XtManageChild (log_form);
00358     }
00359   if (pending_newline)
00360     {
00361       XmTextInsert (log_text, log_size++, "\n");
00362       pending_newline = 0;
00363     }
00364   buf = pcb_vprintf (fmt, ap);
00365   scan = &buf[strlen (buf) - 1];
00366   while (scan >= buf && *scan == '\n')
00367     {
00368       pending_newline++;
00369       *scan-- = 0;
00370     }
00371   XmTextInsert (log_text, log_size, buf);
00372   log_size += strlen (buf);
00373 
00374   scan = strrchr(buf, '\n');
00375   if (scan)
00376     scan++;
00377   else
00378     scan = buf;
00379   XmTextSetCursorPosition (log_text, log_size - strlen(scan));
00380   g_free (buf);
00381 }
00382 
00383 void
00384 lesstif_log (const char *fmt, ...)
00385 {
00386   va_list ap;
00387   va_start (ap, fmt);
00388   lesstif_logv (fmt, ap);
00389   va_end (ap);
00390 }
00391 
00392 /* ------------------------------------------------------------ */
00393 
00394 static Widget confirm_dialog = 0;
00395 static Widget confirm_cancel, confirm_ok, confirm_label;
00396 
00397 int
00398 lesstif_confirm_dialog (char *msg, ...)
00399 {
00400   char *cancelmsg, *okmsg;
00401   va_list ap;
00402   XmString xs;
00403 
00404   if (mainwind == 0)
00405     return 1;
00406 
00407   if (confirm_dialog == 0)
00408     {
00409       n = 0;
00410       stdarg (XmNdefaultButtonType, XmDIALOG_OK_BUTTON);
00411       stdarg (XmNtitle, "Confirm");
00412       confirm_dialog = XmCreateQuestionDialog (mainwind, "confirm", args, n);
00413       XtAddCallback (confirm_dialog, XmNcancelCallback,
00414                      (XtCallbackProc) dialog_callback, (XtPointer) 0);
00415       XtAddCallback (confirm_dialog, XmNokCallback,
00416                      (XtCallbackProc) dialog_callback, (XtPointer) 1);
00417 
00418       confirm_cancel =
00419         XmMessageBoxGetChild (confirm_dialog, XmDIALOG_CANCEL_BUTTON);
00420       confirm_ok = XmMessageBoxGetChild (confirm_dialog, XmDIALOG_OK_BUTTON);
00421       confirm_label =
00422         XmMessageBoxGetChild (confirm_dialog, XmDIALOG_MESSAGE_LABEL);
00423       XtUnmanageChild (XmMessageBoxGetChild
00424                        (confirm_dialog, XmDIALOG_HELP_BUTTON));
00425     }
00426 
00427   va_start (ap, msg);
00428   cancelmsg = va_arg (ap, char *);
00429   okmsg = va_arg (ap, char *);
00430   va_end (ap);
00431 
00432   if (!cancelmsg)
00433     {
00434       cancelmsg = "Cancel";
00435       okmsg = "Ok";
00436     }
00437 
00438   n = 0;
00439   xs = XmStringCreatePCB (cancelmsg);
00440 
00441   if (okmsg)
00442     {
00443       stdarg (XmNcancelLabelString, xs);
00444       xs = XmStringCreatePCB (okmsg);
00445       XtManageChild (confirm_cancel);
00446     }
00447   else
00448     XtUnmanageChild (confirm_cancel);
00449 
00450   stdarg (XmNokLabelString, xs);
00451 
00452   xs = XmStringCreatePCB (msg);
00453   stdarg (XmNmessageString, xs);
00454   XtSetValues (confirm_dialog, args, n);
00455 
00456   wait_for_dialog (confirm_dialog);
00457 
00458   n = 0;
00459   stdarg (XmNdefaultPosition, False);
00460   XtSetValues (confirm_dialog, args, n);
00461 
00462   return ok;
00463 }
00464 
00465 static int
00466 ConfirmAction (int argc, char **argv, Coord x, Coord y)
00467 {
00468   int rv = lesstif_confirm_dialog (argc > 0 ? argv[0] : 0,
00469                                    argc > 1 ? argv[1] : 0,
00470                                    argc > 2 ? argv[2] : 0,
00471                                    0);
00472   return rv;
00473 }
00474 
00475 /* ------------------------------------------------------------ */
00476 
00477 int
00478 lesstif_close_confirm_dialog ()
00479 {
00480   return lesstif_confirm_dialog ("OK to lose data ?", NULL);
00481 }
00482 
00483 /* ------------------------------------------------------------ */
00484 
00485 static Widget report = 0, report_form;
00486 
00487 void
00488 lesstif_report_dialog (char *title, char *msg)
00489 {
00490   if (!report)
00491     {
00492       if (mainwind == 0)
00493         return;
00494 
00495       n = 0;
00496       stdarg (XmNautoUnmanage, False);
00497       stdarg (XmNwidth, 600);
00498       stdarg (XmNheight, 200);
00499       stdarg (XmNtitle, title);
00500       report_form = XmCreateFormDialog (mainwind, "report", args, n);
00501 
00502       n = 0;
00503       stdarg (XmNeditable, False);
00504       stdarg (XmNeditMode, XmMULTI_LINE_EDIT);
00505       stdarg (XmNcursorPositionVisible, False);
00506       stdarg (XmNtopAttachment, XmATTACH_FORM);
00507       stdarg (XmNleftAttachment, XmATTACH_FORM);
00508       stdarg (XmNrightAttachment, XmATTACH_FORM);
00509       stdarg (XmNbottomAttachment, XmATTACH_FORM);
00510       report = XmCreateScrolledText (report_form, "text", args, n);
00511       XtManageChild (report);
00512     }
00513   n = 0;
00514   stdarg (XmNtitle, title);
00515   XtSetValues (report_form, args, n);
00516   XmTextSetString (report, msg);
00517 
00518   XtManageChild (report_form);
00519 }
00520 
00521 /* ------------------------------------------------------------ */
00522 /* FIXME -- make this a proper file select dialog box */
00523 char *
00524 lesstif_fileselect (const char *title, const char *descr,
00525                     char *default_file, char *default_ext,
00526                     const char *history_tag, int flags)
00527 {
00528 
00529   return lesstif_prompt_for (title, default_file);
00530 }
00531 
00532 /* ------------------------------------------------------------ */
00533 
00534 static Widget prompt_dialog = 0;
00535 static Widget prompt_label, prompt_text;
00536 
00537 char *
00538 lesstif_prompt_for (const char *msg, const char *default_string)
00539 {
00540   char *rv;
00541   XmString xs;
00542   if (prompt_dialog == 0)
00543     {
00544       n = 0;
00545       stdarg (XmNautoUnmanage, False);
00546       stdarg (XmNtitle, "PCB Prompt");
00547       prompt_dialog = XmCreateFormDialog (mainwind, "prompt", args, n);
00548 
00549       n = 0;
00550       stdarg (XmNtopAttachment, XmATTACH_FORM);
00551       stdarg (XmNleftAttachment, XmATTACH_FORM);
00552       stdarg (XmNrightAttachment, XmATTACH_FORM);
00553       stdarg (XmNalignment, XmALIGNMENT_BEGINNING);
00554       prompt_label = XmCreateLabel (prompt_dialog, "label", args, n);
00555       XtManageChild (prompt_label);
00556 
00557       n = 0;
00558       stdarg (XmNtopAttachment, XmATTACH_WIDGET);
00559       stdarg (XmNtopWidget, prompt_label);
00560       stdarg (XmNbottomAttachment, XmATTACH_WIDGET);
00561       stdarg (XmNleftAttachment, XmATTACH_FORM);
00562       stdarg (XmNrightAttachment, XmATTACH_FORM);
00563       stdarg (XmNeditable, True);
00564       prompt_text = XmCreateText (prompt_dialog, "text", args, n);
00565       XtManageChild (prompt_text);
00566       XtAddCallback (prompt_text, XmNactivateCallback,
00567                      (XtCallbackProc) dialog_callback, (XtPointer) 1);
00568     }
00569   if (!default_string)
00570     default_string = "";
00571   if (!msg)
00572     msg = "Enter text:";
00573   n = 0;
00574   xs = XmStringCreatePCB ((char *)msg);
00575   stdarg (XmNlabelString, xs);
00576   XtSetValues (prompt_label, args, n);
00577   XmTextSetString (prompt_text, (char *)default_string);
00578   XmTextSetCursorPosition (prompt_text, strlen (default_string));
00579   wait_for_dialog (prompt_dialog);
00580   rv = XmTextGetString (prompt_text);
00581   return rv;
00582 }
00583 
00584 static const char promptfor_syntax[] =
00585 "PromptFor([message[,default]])";
00586 
00587 static const char promptfor_help[] =
00588 "Prompt for a response.";
00589 
00590 /* %start-doc actions PromptFor
00591 
00592 This is mostly for testing the lesstif HID interface.  The parameters
00593 are passed to the @code{prompt_for()} HID function, causing the user
00594 to be prompted for a response.  The respose is simply printed to the
00595 user's stdout.
00596 
00597 %end-doc */
00598 
00599 static int
00600 PromptFor (int argc, char **argv, Coord x, Coord y)
00601 {
00602   char *rv = lesstif_prompt_for (argc > 0 ? argv[0] : 0,
00603                                  argc > 1 ? argv[1] : 0);
00604   printf ("rv = `%s'\n", rv);
00605   return 0;
00606 }
00607 
00608 /* ------------------------------------------------------------ */
00609 
00610 static Widget
00611 create_form_ok_dialog (char *name, int ok)
00612 {
00613   Widget dialog, topform;
00614   n = 0;
00615   dialog = XmCreateQuestionDialog (mainwind, name, args, n);
00616 
00617   XtUnmanageChild (XmMessageBoxGetChild (dialog, XmDIALOG_SYMBOL_LABEL));
00618   XtUnmanageChild (XmMessageBoxGetChild (dialog, XmDIALOG_MESSAGE_LABEL));
00619   XtUnmanageChild (XmMessageBoxGetChild (dialog, XmDIALOG_HELP_BUTTON));
00620   XtAddCallback (dialog, XmNcancelCallback, (XtCallbackProc) dialog_callback,
00621                  (XtPointer) 0);
00622   if (ok)
00623     XtAddCallback (dialog, XmNokCallback, (XtCallbackProc) dialog_callback,
00624                    (XtPointer) 1);
00625   else
00626     XtUnmanageChild (XmMessageBoxGetChild (dialog, XmDIALOG_OK_BUTTON));
00627 
00628   n = 0;
00629   topform = XmCreateForm (dialog, "attributes", args, n);
00630   XtManageChild (topform);
00631   return topform;
00632 }
00633 
00634 int
00635 lesstif_attribute_dialog (HID_Attribute * attrs,
00636                           int n_attrs, HID_Attr_Val * results,
00637                           const char * title, const char * descr)
00638 {
00639   Widget dialog, topform, lform, form;
00640   Widget *wl;
00641   int i, rv;
00642   static XmString empty = 0;
00643   int actual_nattrs = 0;
00644   int attrcount = 0;
00645 
00646   if (!empty)
00647     empty = XmStringCreatePCB (" ");
00648 
00649   for (i = 0; i < n_attrs; i++)
00650     {
00651       if (attrs[i].help_text != ATTR_UNDOCUMENTED)
00652         actual_nattrs ++;
00653       results[i] = attrs[i].default_val;
00654       if (results[i].str_value)
00655         results[i].str_value = strdup (results[i].str_value);
00656     }
00657 
00658   wl = (Widget *) malloc (n_attrs * sizeof (Widget));
00659 
00660   topform = create_form_ok_dialog ((char *)title, 1);
00661   dialog = XtParent (topform);
00662 
00663   n = 0;
00664   stdarg (XmNfractionBase, n_attrs);
00665   XtSetValues (topform, args, n);
00666 
00667   n = 0;
00668   stdarg (XmNtopAttachment, XmATTACH_FORM);
00669   stdarg (XmNbottomAttachment, XmATTACH_FORM);
00670   stdarg (XmNleftAttachment, XmATTACH_FORM);
00671   stdarg (XmNfractionBase, actual_nattrs);
00672   lform = XmCreateForm (topform, "attributes", args, n);
00673   XtManageChild (lform);
00674 
00675   n = 0;
00676   stdarg (XmNtopAttachment, XmATTACH_FORM);
00677   stdarg (XmNbottomAttachment, XmATTACH_FORM);
00678   stdarg (XmNleftAttachment, XmATTACH_WIDGET);
00679   stdarg (XmNleftWidget, lform);
00680   stdarg (XmNrightAttachment, XmATTACH_FORM);
00681   stdarg (XmNfractionBase, actual_nattrs);
00682   form = XmCreateForm (topform, "attributes", args, n);
00683   XtManageChild (form);
00684 
00685   attrcount = -1;
00686   for (i = 0; i < n_attrs; i++)
00687     {
00688       Widget w;
00689 
00690       if (attrs[i].help_text == ATTR_UNDOCUMENTED)
00691         continue;
00692       attrcount ++;
00693 
00694       n = 0;
00695       stdarg (XmNleftAttachment, XmATTACH_FORM);
00696       stdarg (XmNrightAttachment, XmATTACH_FORM);
00697       stdarg (XmNtopAttachment, XmATTACH_POSITION);
00698       stdarg (XmNtopPosition, attrcount);
00699       stdarg (XmNbottomAttachment, XmATTACH_POSITION);
00700       stdarg (XmNbottomPosition, attrcount + 1);
00701       stdarg (XmNalignment, XmALIGNMENT_END);
00702       w = XmCreateLabel (lform, attrs[i].name, args, n);
00703       XtManageChild (w);
00704     }
00705 
00706   attrcount = -1;
00707   for (i = 0; i < n_attrs; i++)
00708     {
00709       static char buf[30];
00710       n = 0;
00711 
00712       if (attrs[i].help_text == ATTR_UNDOCUMENTED)
00713         continue;
00714       attrcount ++;
00715 
00716       stdarg (XmNleftAttachment, XmATTACH_FORM);
00717       stdarg (XmNrightAttachment, XmATTACH_FORM);
00718       stdarg (XmNtopAttachment, XmATTACH_POSITION);
00719       stdarg (XmNtopPosition, attrcount);
00720       stdarg (XmNbottomAttachment, XmATTACH_POSITION);
00721       stdarg (XmNbottomPosition, attrcount + 1);
00722       stdarg (XmNalignment, XmALIGNMENT_END);
00723 
00724       switch (attrs[i].type)
00725         {
00726         case HID_Label:
00727           stdarg (XmNlabelString, empty);
00728           wl[i] = XmCreateLabel (form, attrs[i].name, args, n);
00729           break;
00730         case HID_Boolean:
00731           stdarg (XmNlabelString, empty);
00732           stdarg (XmNset, results[i].int_value);
00733           wl[i] = XmCreateToggleButton (form, attrs[i].name, args, n);
00734           break;
00735         case HID_String:
00736           stdarg (XmNcolumns, 40);
00737           stdarg (XmNresizeWidth, True);
00738           stdarg (XmNvalue, results[i].str_value);
00739           wl[i] = XmCreateTextField (form, attrs[i].name, args, n);
00740           break;
00741         case HID_Integer:
00742           stdarg (XmNcolumns, 13);
00743           stdarg (XmNresizeWidth, True);
00744           sprintf (buf, "%d", results[i].int_value);
00745           stdarg (XmNvalue, buf);
00746           wl[i] = XmCreateTextField (form, attrs[i].name, args, n);
00747           break;
00748         case HID_Coord:
00749           stdarg (XmNcolumns, 13);
00750           stdarg (XmNresizeWidth, True);
00751           pcb_snprintf (buf, sizeof (buf), "%$mS", results[i].coord_value);
00752           stdarg (XmNvalue, buf);
00753           wl[i] = XmCreateTextField (form, attrs[i].name, args, n);
00754           break;
00755         case HID_Real:
00756           stdarg (XmNcolumns, 16);
00757           stdarg (XmNresizeWidth, True);
00758           sprintf (buf, "%g", results[i].real_value);
00759           stdarg (XmNvalue, buf);
00760           wl[i] = XmCreateTextField (form, attrs[i].name, args, n);
00761           break;
00762         case HID_Enum:
00763           {
00764             static XmString empty = 0;
00765             Widget submenu, default_button=0;
00766             int sn = n;
00767 
00768             if (empty == 0)
00769               empty = XmStringCreatePCB ("");
00770 
00771             submenu = XmCreatePulldownMenu (form, attrs[i].name, args+sn, n-sn);
00772 
00773             n = sn;
00774             stdarg (XmNlabelString, empty);
00775             stdarg (XmNsubMenuId, submenu);
00776             wl[i] = XmCreateOptionMenu (form, attrs[i].name, args, n);
00777 
00778             for (sn=0; attrs[i].enumerations[sn]; sn++)
00779               {
00780                 Widget btn;
00781                 XmString label;
00782                 n = 0;
00783                 label = XmStringCreatePCB ((char *)attrs[i].enumerations[sn]);
00784                 stdarg (XmNuserData, & attrs[i].enumerations[sn]);
00785                 stdarg (XmNlabelString, label);
00786                 btn = XmCreatePushButton (submenu, "menubutton", args, n);
00787                 XtManageChild (btn);
00788                 XmStringFree (label);
00789                 if (sn == attrs[i].default_val.int_value)
00790                   default_button = btn;
00791               }
00792             if (default_button)
00793               {
00794                 n = 0;
00795                 stdarg (XmNmenuHistory, default_button);
00796                 XtSetValues (wl[i], args, n);
00797               }
00798           }
00799           break;
00800         default:
00801           wl[i] = XmCreateLabel (form, "UNIMPLEMENTED", args, n);
00802           break;
00803         }
00804 
00805       XtManageChild (wl[i]);
00806     }
00807 
00808   rv = wait_for_dialog (dialog);
00809 
00810   for (i = 0; i < n_attrs; i++)
00811     {
00812       char *cp;
00813 
00814       if (attrs[i].help_text == ATTR_UNDOCUMENTED)
00815         continue;
00816 
00817       switch (attrs[i].type)
00818         {
00819         case HID_Boolean:
00820           results[i].int_value = XmToggleButtonGetState (wl[i]);
00821           break;
00822         case HID_String:
00823           results[i].str_value = XmTextGetString (wl[i]);
00824           break;
00825         case HID_Integer:
00826           cp = XmTextGetString (wl[i]);
00827           sscanf (cp, "%d", &results[i].int_value);
00828           break;
00829         case HID_Coord:
00830           cp = XmTextGetString (wl[i]);
00831           results[i].coord_value = GetValue (cp, NULL, NULL);
00832           break;
00833         case HID_Real:
00834           cp = XmTextGetString (wl[i]);
00835           sscanf (cp, "%lg", &results[i].real_value);
00836           break;
00837         case HID_Enum:
00838           {
00839             const char **uptr;
00840             Widget btn;
00841 
00842             n = 0;
00843             stdarg (XmNmenuHistory, &btn);
00844             XtGetValues (wl[i], args, n);
00845             n = 0;
00846             stdarg (XmNuserData, &uptr);
00847             XtGetValues (btn, args, n);
00848             results[i].int_value = uptr - attrs[i].enumerations;
00849           }
00850           break;
00851         default:
00852           break;
00853         }
00854     }
00855 
00856   free (wl);
00857   XtDestroyWidget (dialog);
00858 
00859   return rv ? 0 : 1;
00860 }
00861 
00862 /* ------------------------------------------------------------ */
00863 
00864 static const char dowindows_syntax[] =
00865 "DoWindows(1|2|3|4)\n"
00866 "DoWindows(Layout|Library|Log|Netlist)";
00867 
00868 static const char dowindows_help[] =
00869 "Open various GUI windows.";
00870 
00871 /* %start-doc actions DoWindows
00872 
00873 @table @code
00874 
00875 @item 1
00876 @itemx Layout
00877 Open the layout window.  Since the layout window is always shown
00878 anyway, this has no effect.
00879 
00880 @item 2
00881 @itemx Library
00882 Open the library window.
00883 
00884 @item 3
00885 @itemx Log
00886 Open the log window.
00887 
00888 @item 4
00889 @itemx Netlist
00890 Open the netlist window.
00891 
00892 @end table
00893 
00894 %end-doc */
00895 
00896 static int
00897 DoWindows (int argc, char **argv, Coord x, Coord y)
00898 {
00899   const char *a = argc == 1 ? argv[0] : "";
00900   if (strcmp (a, "1") == 0 || strcasecmp (a, "Layout") == 0)
00901     {
00902     }
00903   else if (strcmp (a, "2") == 0 || strcasecmp (a, "Library") == 0)
00904     {
00905       lesstif_show_library ();
00906     }
00907   else if (strcmp (a, "3") == 0 || strcasecmp (a, "Log") == 0)
00908     {
00909       if (log_form == 0)
00910         lesstif_log ("");
00911       XtManageChild (log_form);
00912     }
00913   else if (strcmp (a, "4") == 0 || strcasecmp (a, "Netlist") == 0)
00914     {
00915       lesstif_show_netlist ();
00916     }
00917   else
00918     {
00919       lesstif_log ("Usage: DoWindows(1|2|3|4|Layout|Library|Log|Netlist)");
00920       return 1;
00921     }
00922   return 0;
00923 }
00924 
00925 /* ------------------------------------------------------------ */
00926 static const char about_syntax[] =
00927 "About()";
00928 
00929 static const char about_help[] =
00930 "Tell the user about this version of PCB.";
00931 
00932 /* %start-doc actions About
00933 
00934 This just pops up a dialog telling the user which version of
00935 @code{pcb} they're running.
00936 
00937 %end-doc */
00938 
00939 
00940 static int
00941 About (int argc, char **argv, Coord x, Coord y)
00942 {
00943   static Widget about = 0;
00944   if (!about)
00945     {
00946       Cardinal n = 0;
00947       XmString xs = XmStringCreatePCB (GetInfoString ());
00948       stdarg (XmNmessageString, xs);
00949       stdarg (XmNtitle, "About PCB");
00950       about = XmCreateInformationDialog (mainwind, "about", args, n);
00951       XtUnmanageChild (XmMessageBoxGetChild (about, XmDIALOG_CANCEL_BUTTON));
00952       XtUnmanageChild (XmMessageBoxGetChild (about, XmDIALOG_HELP_BUTTON));
00953     }
00954   wait_for_dialog (about);
00955   return 0;
00956 }
00957 
00958 /* ------------------------------------------------------------ */
00959 
00960 static const char print_syntax[] =
00961 "Print()";
00962 
00963 static const char print_help[] =
00964 "Print the layout.";
00965 
00966 /* %start-doc actions Print
00967 
00968 This will find the default printing HID, prompt the user for its
00969 options, and print the layout.
00970 
00971 %end-doc */
00972 
00973 static int
00974 Print (int argc, char **argv, Coord x, Coord y)
00975 {
00976   HID_Attribute *opts;
00977   HID *printer;
00978   HID_Attr_Val *vals;
00979   int n;
00980 
00981   printer = hid_find_printer ();
00982   if (!printer)
00983     {
00984       lesstif_confirm_dialog ("No printer?", "Oh well", 0);
00985       return 1;
00986     }
00987   opts = printer->get_export_options (&n);
00988   vals = (HID_Attr_Val *) calloc (n, sizeof (HID_Attr_Val));
00989   if (lesstif_attribute_dialog (opts, n, vals, "Print", ""))
00990     {
00991       free (vals);
00992       return 1;
00993     }
00994   printer->do_export (vals);
00995   free (vals);
00996   return 0;
00997 }
00998 
00999 static HID_Attribute
01000 printer_calibrate_attrs[] = {
01001   {"Enter Values here:", "",
01002    HID_Label, 0, 0, {0, 0, 0}, 0, 0},
01003   {"x-calibration", "X scale for calibrating your printer",
01004    HID_Real, 0.5, 25, {0, 0, 1.00}, 0, 0},
01005   {"y-calibration", "Y scale for calibrating your printer",
01006    HID_Real, 0.5, 25, {0, 0, 1.00}, 0, 0}
01007 };
01008 static HID_Attr_Val printer_calibrate_values[3];
01009 
01010 static const char printcalibrate_syntax[] =
01011 "PrintCalibrate()";
01012 
01013 static const char printcalibrate_help[] =
01014 "Calibrate the printer.";
01015 
01016 /* %start-doc actions PrintCalibrate
01017 
01018 This will print a calibration page, which you would measure and type
01019 the measurements in, so that future printouts will be more precise.
01020 
01021 %end-doc */
01022 
01023 static int
01024 PrintCalibrate (int argc, char **argv, Coord x, Coord y)
01025 {
01026   HID *printer = hid_find_printer ();
01027   printer->calibrate (0.0, 0.0);
01028   if (gui->attribute_dialog (printer_calibrate_attrs, 3,
01029                              printer_calibrate_values,
01030                              "Printer Calibration Values", "Enter calibration values for your printer"))
01031     return 1;
01032   printer->calibrate (printer_calibrate_values[1].real_value,
01033                       printer_calibrate_values[2].real_value);
01034   return 0;
01035 }
01036 
01037 static const char export_syntax[] =
01038 "Export()";
01039 
01040 static const char export_help[] =
01041 "Export the layout.";
01042 
01043 /* %start-doc actions Export
01044 
01045 Prompts the user for an exporter to use.  Then, prompts the user for
01046 that exporter's options, and exports the layout.
01047 
01048 %end-doc */
01049 
01050 static int
01051 Export (int argc, char **argv, Coord x, Coord y)
01052 {
01053   static Widget selector = 0;
01054   HID_Attribute *opts;
01055   HID *printer, **hids;
01056   HID_Attr_Val *vals;
01057   int n, i;
01058   Widget prev = 0;
01059   Widget w;
01060 
01061   hids = hid_enumerate ();
01062 
01063   if (!selector)
01064     {
01065       n = 0;
01066       stdarg (XmNtitle, "Export HIDs");
01067       selector = create_form_ok_dialog ("export", 0);
01068       for (i = 0; hids[i]; i++)
01069         {
01070           if (hids[i]->exporter)
01071             {
01072               n = 0;
01073               if (prev)
01074                 {
01075                   stdarg (XmNtopAttachment, XmATTACH_WIDGET);
01076                   stdarg (XmNtopWidget, prev);
01077                 }
01078               else
01079                 {
01080                   stdarg (XmNtopAttachment, XmATTACH_FORM);
01081                 }
01082               stdarg (XmNrightAttachment, XmATTACH_FORM);
01083               stdarg (XmNleftAttachment, XmATTACH_FORM);
01084               w =
01085                 XmCreatePushButton (selector, (char *) hids[i]->name, args,
01086                                     n);
01087               XtManageChild (w);
01088               XtAddCallback (w, XmNactivateCallback,
01089                              (XtCallbackProc) dialog_callback,
01090                              (XtPointer) ((size_t) i + 1));
01091               prev = w;
01092             }
01093         }
01094       selector = XtParent (selector);
01095     }
01096 
01097   i = wait_for_dialog (selector);
01098 
01099   if (i <= 0)
01100     return 1;
01101   printer = hids[i - 1];
01102 
01103   exporter = printer;
01104 
01105   opts = printer->get_export_options (&n);
01106   vals = (HID_Attr_Val *) calloc (n, sizeof (HID_Attr_Val));
01107   if (lesstif_attribute_dialog (opts, n, vals, "Export", NULL))
01108     {
01109       free (vals);
01110       return 1;
01111     }
01112   printer->do_export (vals);
01113   free (vals);
01114   exporter = NULL;
01115   return 0;
01116 }
01117 
01118 /* ------------------------------------------------------------ */
01119 
01120 static Widget sizes_dialog = 0;
01121 static Widget sz_pcb_w, sz_pcb_h, sz_bloat, sz_shrink, sz_drc_wid, sz_drc_slk,
01122   sz_drc_drill, sz_drc_ring;
01123 static Widget sz_text;
01124 static Widget sz_set, sz_reset, sz_units;
01125 
01126 static int
01127 sz_str2val (Widget w, bool pcbu)
01128 {
01129   char *buf = XmTextGetString (w);
01130   if (!pcbu)
01131     return strtol (buf, NULL, 0);
01132   return GetValueEx (buf, NULL, NULL, NULL, Settings.grid_unit->suffix);
01133 }
01134 
01135 static void
01136 sz_val2str (Widget w, Coord u, int pcbu)
01137 {
01138   static char buf[40];
01139   if (pcbu)
01140     pcb_snprintf (buf, sizeof (buf), "%m+%.2mS", Settings.grid_unit->allow, u);
01141   else
01142     pcb_snprintf (buf, sizeof (buf), "%#mS %%", u);
01143   XmTextSetString (w, buf);
01144 }
01145 
01146 static void
01147 sizes_set ()
01148 {
01149   PCB->MaxWidth = sz_str2val (sz_pcb_w, 1);
01150   PCB->MaxHeight = sz_str2val (sz_pcb_h, 1);
01151   PCB->Bloat = sz_str2val (sz_bloat, 1);
01152   PCB->Shrink = sz_str2val (sz_shrink, 1);
01153   PCB->minWid = sz_str2val (sz_drc_wid, 1);
01154   PCB->minSlk = sz_str2val (sz_drc_slk, 1);
01155   PCB->minDrill = sz_str2val (sz_drc_drill, 1);
01156   PCB->minRing = sz_str2val (sz_drc_ring, 1);
01157   Settings.TextScale = sz_str2val (sz_text, 0);
01158 
01159   Settings.Bloat = PCB->Bloat;
01160   Settings.Shrink = PCB->Shrink;
01161   Settings.minWid = PCB->minWid;
01162   Settings.minSlk = PCB->minSlk;
01163   Settings.minDrill = PCB->minDrill;
01164   Settings.minRing = PCB->minRing;
01165 
01166   crosshair_update_range();
01167   lesstif_pan_fixup ();
01168 }
01169 
01170 void
01171 lesstif_sizes_reset ()
01172 {
01173   char *ls;
01174   if (!sizes_dialog)
01175     return;
01176   sz_val2str (sz_pcb_w, PCB->MaxWidth, 1);
01177   sz_val2str (sz_pcb_h, PCB->MaxHeight, 1);
01178   sz_val2str (sz_bloat, PCB->Bloat, 1);
01179   sz_val2str (sz_shrink, PCB->Shrink, 1);
01180   sz_val2str (sz_drc_wid, PCB->minWid, 1);
01181   sz_val2str (sz_drc_slk, PCB->minSlk, 1);
01182   sz_val2str (sz_drc_drill, PCB->minDrill, 1);
01183   sz_val2str (sz_drc_ring, PCB->minRing, 1);
01184   sz_val2str (sz_text, Settings.TextScale, 0);
01185 
01186   ls = g_strdup_printf (_("Units are %s."), Settings.grid_unit->in_suffix);
01187   n = 0;
01188   stdarg (XmNlabelString, XmStringCreatePCB (ls));
01189   XtSetValues (sz_units, args, n);
01190   g_free (ls);
01191 }
01192 
01193 static Widget
01194 size_field (Widget parent, char *label, int posn)
01195 {
01196   Widget w, l;
01197   n = 0;
01198   stdarg (XmNrightAttachment, XmATTACH_FORM);
01199   stdarg (XmNtopAttachment, XmATTACH_POSITION);
01200   stdarg (XmNtopPosition, posn);
01201   stdarg (XmNbottomAttachment, XmATTACH_POSITION);
01202   stdarg (XmNbottomPosition, posn + 1);
01203   stdarg (XmNcolumns, 10);
01204   w = XmCreateTextField (parent, "field", args, n);
01205   XtManageChild (w);
01206 
01207   n = 0;
01208   stdarg (XmNleftAttachment, XmATTACH_FORM);
01209   stdarg (XmNrightAttachment, XmATTACH_WIDGET);
01210   stdarg (XmNrightWidget, w);
01211   stdarg (XmNtopAttachment, XmATTACH_POSITION);
01212   stdarg (XmNtopPosition, posn);
01213   stdarg (XmNbottomAttachment, XmATTACH_POSITION);
01214   stdarg (XmNbottomPosition, posn + 1);
01215   stdarg (XmNlabelString, XmStringCreatePCB (label));
01216   stdarg (XmNalignment, XmALIGNMENT_END);
01217   l = XmCreateLabel (parent, "label", args, n);
01218   XtManageChild (l);
01219 
01220   return w;
01221 }
01222 
01223 static const char adjustsizes_syntax[] =
01224 "AdjustSizes()";
01225 
01226 static const char adjustsizes_help[] =
01227 "Let the user change the board size, DRC parameters, etc";
01228 
01229 /* %start-doc actions AdjustSizes
01230 
01231 Displays a dialog box that lets the user change the board
01232 size, DRC parameters, and text scale.
01233 
01234 The units are determined by the default display units.
01235 
01236 %end-doc */
01237 
01238 static int
01239 AdjustSizes (int argc, char **argv, Coord x, Coord y)
01240 {
01241   if (!sizes_dialog)
01242     {
01243       Widget inf, sep;
01244 
01245       n = 0;
01246       stdarg (XmNmarginWidth, 3);
01247       stdarg (XmNmarginHeight, 3);
01248       stdarg (XmNhorizontalSpacing, 3);
01249       stdarg (XmNverticalSpacing, 3);
01250       stdarg (XmNautoUnmanage, False);
01251       stdarg (XmNtitle, "Board Sizes");
01252       sizes_dialog = XmCreateFormDialog (mainwind, "sizes", args, n);
01253 
01254       n = 0;
01255       stdarg (XmNrightAttachment, XmATTACH_FORM);
01256       stdarg (XmNbottomAttachment, XmATTACH_FORM);
01257       sz_reset = XmCreatePushButton (sizes_dialog, "Reset", args, n);
01258       XtManageChild (sz_reset);
01259       XtAddCallback (sz_reset, XmNactivateCallback,
01260                      (XtCallbackProc) lesstif_sizes_reset, 0);
01261 
01262       n = 0;
01263       stdarg (XmNrightAttachment, XmATTACH_WIDGET);
01264       stdarg (XmNrightWidget, sz_reset);
01265       stdarg (XmNbottomAttachment, XmATTACH_FORM);
01266       sz_set = XmCreatePushButton (sizes_dialog, "Set", args, n);
01267       XtManageChild (sz_set);
01268       XtAddCallback (sz_set, XmNactivateCallback, (XtCallbackProc) sizes_set,
01269                      0);
01270 
01271       n = 0;
01272       stdarg (XmNrightAttachment, XmATTACH_FORM);
01273       stdarg (XmNleftAttachment, XmATTACH_FORM);
01274       stdarg (XmNbottomAttachment, XmATTACH_WIDGET);
01275       stdarg (XmNbottomWidget, sz_reset);
01276       sep = XmCreateSeparator (sizes_dialog, "sep", args, n);
01277       XtManageChild (sep);
01278 
01279       n = 0;
01280       stdarg (XmNrightAttachment, XmATTACH_FORM);
01281       stdarg (XmNleftAttachment, XmATTACH_FORM);
01282       stdarg (XmNbottomAttachment, XmATTACH_WIDGET);
01283       stdarg (XmNbottomWidget, sep);
01284       sz_units = XmCreateLabel (sizes_dialog, "units", args, n);
01285       XtManageChild (sz_units);
01286 
01287       n = 0;
01288       stdarg (XmNrightAttachment, XmATTACH_FORM);
01289       stdarg (XmNleftAttachment, XmATTACH_FORM);
01290       stdarg (XmNtopAttachment, XmATTACH_FORM);
01291       stdarg (XmNbottomAttachment, XmATTACH_WIDGET);
01292       stdarg (XmNbottomWidget, sz_units);
01293       stdarg (XmNfractionBase, 9);
01294       inf = XmCreateForm (sizes_dialog, "sizes", args, n);
01295       XtManageChild (inf);
01296 
01297       sz_pcb_w = size_field (inf, "PCB Width", 0);
01298       sz_pcb_h = size_field (inf, "PCB Height", 1);
01299       sz_bloat = size_field (inf, "Bloat", 2);
01300       sz_shrink = size_field (inf, "Shrink", 3);
01301       sz_drc_wid = size_field (inf, "DRC Min Wid", 4);
01302       sz_drc_slk = size_field (inf, "DRC Min Silk", 5);
01303       sz_drc_drill = size_field (inf, "DRC Min Drill", 6);
01304       sz_drc_ring = size_field (inf, "DRC Min Annular Ring", 7);
01305       sz_text = size_field (inf, "Text Scale", 8);
01306     }
01307   lesstif_sizes_reset ();
01308   XtManageChild (sizes_dialog);
01309   return 0;
01310 }
01311 
01312 /* ------------------------------------------------------------ */
01313 
01314 static Widget layer_groups_form = 0;
01315 static Widget lg_buttonform = 0;
01316 
01317 static int lg_setcol[MAX_ALL_LAYER];
01318 static int lg_width, lg_height;
01319 static int lg_r[MAX_ALL_LAYER + 1];
01320 static int lg_c[MAX_ALL_LAYER + 1];
01321 static int lg_label_width, lg_fa, lg_fd;
01322 static GC lg_gc = 0;
01323 
01324 #if 0
01325 static Widget lglabels[MAX_ALL_LAYER];
01326 static Widget lgbuttons[MAX_ALL_LAYER][MAX_GROUP];
01327 #endif
01328 
01329 typedef struct {
01330   XFontStruct *font;
01331   Pixel fg, bg, sel;
01332 } LgResource;
01333 
01334 static LgResource lgr;
01335 
01336 static XtResource lg_resources[] = {
01337   { "font", "Font", XtRFontStruct, sizeof(XFontStruct*), XtOffset(LgResource*, font), XtRString, (void *)"fixed" },
01338   { "foreground", "Foreground", XtRPixel, sizeof(Pixel), XtOffset(LgResource*, fg), XtRString, (void *)"black" },
01339   { "selectColor", "Foreground", XtRPixel, sizeof(Pixel), XtOffset(LgResource*, sel), XtRString, (void *)"blue" },
01340   { "background", "Background", XtRPixel, sizeof(Pixel), XtOffset(LgResource*, bg), XtRString, (void *)"white" }
01341 };
01342 
01343 #if 0
01344 static void
01345 lgbutton_cb (Widget w, int ij, void *cbs)
01346 {
01347   int layer, group, k;
01348 
01349   layer = ij / max_group;
01350   group = ij % max_group;
01351   group = MoveLayerToGroup (layer, group);
01352   for (k = 0; k < max_group; k++)
01353     {
01354       if (k == group)
01355         XmToggleButtonSetState (lgbuttons[layer][k], 1, 0);
01356       else
01357         XmToggleButtonSetState (lgbuttons[layer][k], 0, 0);
01358     }
01359 }
01360 #endif
01361 
01362 static void
01363 lgbutton_expose (Widget w, XtPointer u, XmDrawingAreaCallbackStruct *cbs)
01364 {
01365   int i;
01366   Window win = XtWindow(w);
01367 
01368   if (cbs && cbs->event->xexpose.count)
01369     return;
01370   if (lg_gc == 0 && !cbs)
01371     return;
01372   if (lg_gc == 0 && cbs)
01373     {
01374       lg_gc = XCreateGC (display, win, 0, 0);
01375       XSetFont (display, lg_gc, lgr.font->fid);
01376     }
01377 
01378   XSetForeground (display, lg_gc, lgr.bg);
01379   XFillRectangle (display, win, lg_gc, 0, 0, lg_width, lg_height);
01380   XSetForeground (display, lg_gc, lgr.fg);
01381   for (i = 0; i < max_group; i++)
01382     XDrawLine(display, win, lg_gc, lg_c[i], 0, lg_c[i], lg_height);
01383   for (i = 1; i < max_copper_layer + SILK_LAYER; i++)
01384     XDrawLine(display, win, lg_gc, lg_label_width, lg_r[i], lg_width, lg_r[i]);
01385   for (i = 0; i < max_copper_layer + SILK_LAYER; i++)
01386     {
01387       int dir;
01388       XCharStruct size;
01389       int swidth;
01390       const char *name;
01391 
01392       if (i == bottom_silk_layer)
01393         name = BOTTOM_SIDE_NAME;
01394       else if (i == top_silk_layer)
01395         name = TOP_SIDE_NAME;
01396       else
01397         name = PCB->Data->Layer[i].Name;
01398       XTextExtents (lgr.font, name, strlen(name), &dir, &lg_fa, &lg_fd, &size);
01399       swidth = size.rbearing - size.lbearing;
01400       XDrawString(display, win, lg_gc,
01401                   (lg_label_width - swidth)/2 - size.lbearing,
01402                   (lg_r[i] + lg_r[i+1] + lg_fd + lg_fa)/2 - 1,
01403                   name, strlen(name));
01404     }
01405   XSetForeground (display, lg_gc, lgr.sel);
01406   for (i = 0; i < max_copper_layer + SILK_LAYER; i++)
01407     {
01408       int c = lg_setcol[i];
01409       int x1 = lg_c[c] + 2;
01410       int x2 = lg_c[c+1] - 2;
01411       int y1 = lg_r[i] + 2;
01412       int y2 = lg_r[i+1] - 2;
01413       XFillRectangle (display, win, lg_gc, x1, y1, x2-x1+1, y2-y1+1);
01414     }
01415 }
01416 
01417 static void
01418 lgbutton_input (Widget w, XtPointer u, XmDrawingAreaCallbackStruct *cbs)
01419 {
01420   int layer, group;
01421   if (cbs->event->type != ButtonPress)
01422     return;
01423   layer = cbs->event->xbutton.y * (max_copper_layer + SILK_LAYER) /
01424           lg_height;
01425   group = (cbs->event->xbutton.x - lg_label_width) * max_group / (lg_width - lg_label_width);
01426   group = MoveLayerToGroup (layer, group);
01427   lg_setcol[layer] = group;
01428   lgbutton_expose (w, 0, 0);
01429   gui->invalidate_all ();
01430 }
01431 
01432 static void
01433 lgbutton_resize (Widget w, XtPointer u, XmDrawingAreaCallbackStruct *cbs)
01434 {
01435   int i;
01436   Dimension width, height;
01437   n = 0;
01438   stdarg(XmNwidth, &width);
01439   stdarg(XmNheight, &height);
01440   XtGetValues(w, args, n);
01441   lg_width = width;
01442   lg_height = height;
01443 
01444   for (i=0; i<=max_group; i++)
01445     lg_c[i] = lg_label_width + (lg_width - lg_label_width) * i / max_group;
01446   for (i=0; i<=max_copper_layer + SILK_LAYER; i++)
01447     lg_r[i] = lg_height * i / (max_copper_layer + SILK_LAYER);
01448   lgbutton_expose (w, 0, 0);
01449 }
01450 
01451 void
01452 lesstif_update_layer_groups ()
01453 {
01454   int sets[MAX_ALL_LAYER][MAX_GROUP];
01455   int i, j, n;
01456   LayerGroupType *l = &(PCB->LayerGroups);
01457 
01458   if (!layer_groups_form)
01459     return;
01460 
01461   memset (sets, 0, sizeof (sets));
01462 
01463   for (i = 0; i < max_group; i++)
01464     for (j = 0; j < l->Number[i]; j++)
01465       {
01466         sets[l->Entries[i][j]][i] = 1;
01467         lg_setcol[l->Entries[i][j]] = i;
01468       }
01469 
01470   lg_label_width = 0;
01471   for (i = 0; i < max_copper_layer + SILK_LAYER; i++)
01472     {
01473       int dir;
01474       XCharStruct size;
01475       int swidth;
01476       const char *name;
01477 
01478       if (i == bottom_silk_layer)
01479         name = BOTTOM_SIDE_NAME;
01480       else if (i == top_silk_layer)
01481         name = TOP_SIDE_NAME;
01482       else
01483         name = PCB->Data->Layer[i].Name;
01484       XTextExtents (lgr.font, name, strlen(name), &dir, &lg_fa, &lg_fd, &size);
01485       swidth = size.rbearing - size.lbearing;
01486       if (lg_label_width < swidth)
01487         lg_label_width = swidth;
01488     }
01489   lg_label_width += 4;
01490 
01491   n = 0;
01492   stdarg(XmNwidth, lg_label_width + (lg_fa+lg_fd) * max_group);
01493   stdarg(XmNheight, (lg_fa+lg_fd) * (max_copper_layer + SILK_LAYER));
01494   XtSetValues(lg_buttonform, args, n);
01495   lgbutton_expose (lg_buttonform, 0, 0);
01496 
01497 #if 0
01498   for (i = 0; i < max_copper_layer + SILK_LAYER; i++)
01499     {
01500       char *name = "unknown";
01501       n = 0;
01502       if (i < max_copper_layer)
01503         name = PCB->Data->Layer[i].Name;
01504       else if (i == bottom_silk_layer)
01505         name = BOTTOM_SIDE_NAME;
01506       else if (i == top_silk_layer)
01507         name = TOP_SIDE_NAME;
01508       stdarg (XmNlabelString, XmStringCreatePCB (name));
01509       XtSetValues (lglabels[i], args, n);
01510       for (j = 0; j < max_group; j++)
01511         {
01512           if (sets[i][j] != XmToggleButtonGetState (lgbuttons[i][j]))
01513             {
01514               XmToggleButtonSetState (lgbuttons[i][j], sets[i][j], 0);
01515             }
01516         }
01517     }
01518   XtUnmanageChild(lg_buttonform);
01519   for (i = 0; i < MAX_ALL_LAYER; i++)
01520     for (j = 0; j < MAX_GROUP; j++)
01521       {
01522         if (i < max_copper_layer + SILK_LAYER && j < max_group)
01523           {
01524             XtManageChild(lgbuttons[i][j]);
01525             n = 0;
01526             stdarg (XmNleftPosition, j * (max_copper_layer + SILK_LAYER));
01527             stdarg (XmNrightPosition, (j + 1) * (max_copper_layer + SILK_LAYER));
01528             stdarg (XmNtopPosition, i * max_group);
01529             stdarg (XmNbottomPosition, (i + 1) * max_group);
01530             XtSetValues(lgbuttons[i][j], args, n);
01531           }
01532         else
01533           XtUnmanageChild(lgbuttons[i][j]);
01534       }
01535   n = 0;
01536   stdarg (XmNfractionBase, max_copper_layer + SILK_LAYER);
01537   XtSetValues (layer_groups_form, args, n);
01538   n = 0;
01539   stdarg (XmNfractionBase, max_group * (max_copper_layer + SILK_LAYER));
01540   XtSetValues (lg_buttonform, args, n);
01541   XtManageChild(lg_buttonform);
01542 #endif
01543 }
01544 
01545 static const char editlayergroups_syntax[] =
01546 "EditLayerGroups()";
01547 
01548 static const char editlayergroups_help[] =
01549 "Let the user change the layer groupings";
01550 
01551 /* %start-doc actions EditLayerGroups
01552 
01553 Displays a dialog that lets the user view and change the layer
01554 groupings.  Each layer (row) can be a member of any one layer group
01555 (column).  Note the special layers @code{solder} and @code{component}
01556 allow you to specify which groups represent the top and bottom of the
01557 board.
01558 
01559 See @ref{ChangeName Action}.
01560 
01561 %end-doc */
01562 
01563 static int
01564 EditLayerGroups (int argc, char **argv, Coord x, Coord y)
01565 {
01566   if (!layer_groups_form)
01567     {
01568 
01569       n = 0;
01570       stdarg (XmNfractionBase, max_copper_layer + SILK_LAYER);
01571       stdarg (XmNtitle, "Layer Groups");
01572       layer_groups_form = XmCreateFormDialog (mainwind, "layers", args, n);
01573 
01574       n = 0;
01575       stdarg (XmNtopAttachment, XmATTACH_FORM);
01576       stdarg (XmNbottomAttachment, XmATTACH_FORM);
01577       stdarg (XmNrightAttachment, XmATTACH_FORM);
01578       stdarg (XmNleftAttachment, XmATTACH_FORM);
01579       lg_buttonform = XmCreateDrawingArea (layer_groups_form, "layers", args, n);
01580       XtManageChild (lg_buttonform);
01581 
01582       XtAddCallback (lg_buttonform, XmNexposeCallback,
01583                      (XtCallbackProc) lgbutton_expose, 0);
01584       XtAddCallback (lg_buttonform, XmNinputCallback,
01585                      (XtCallbackProc) lgbutton_input, 0);
01586       XtAddCallback (lg_buttonform, XmNresizeCallback,
01587                      (XtCallbackProc) lgbutton_resize, 0);
01588 
01589       XtGetSubresources (layer_groups_form, &lgr,
01590                          "layergroups", "LayerGroups",
01591                          lg_resources, XtNumber(lg_resources), 0, 0);
01592 #if 0
01593       stdarg (XmNfractionBase, max_group * (MAX_ALL_LAYER));
01594       lg_buttonform = XmCreateForm (layer_groups_form, "lgbutton", args, n);
01595 
01596       for (i = 0; i < MAX_ALL_LAYER; i++)
01597         {
01598           n = 0;
01599           stdarg (XmNleftAttachment, XmATTACH_FORM);
01600           stdarg (XmNtopAttachment, XmATTACH_POSITION);
01601           stdarg (XmNtopPosition, i);
01602           stdarg (XmNbottomAttachment, XmATTACH_POSITION);
01603           stdarg (XmNbottomPosition, i + 1);
01604           stdarg (XmNrightAttachment, XmATTACH_WIDGET);
01605           stdarg (XmNrightWidget, lg_buttonform);
01606           lglabels[i] = XmCreateLabel (layer_groups_form, "layer", args, n);
01607           XtManageChild (lglabels[i]);
01608 
01609           for (j = 0; j < MAX_GROUP; j++)
01610             {
01611               n = 0;
01612               stdarg (XmNleftAttachment, XmATTACH_POSITION);
01613               stdarg (XmNleftPosition, j * (MAX_LAYER));
01614               stdarg (XmNrightAttachment, XmATTACH_POSITION);
01615               stdarg (XmNrightPosition, (j + 1) * (MAX_LAYER));
01616               stdarg (XmNtopAttachment, XmATTACH_POSITION);
01617               stdarg (XmNtopPosition, i * MAX_LAYER);
01618               stdarg (XmNbottomAttachment, XmATTACH_POSITION);
01619               stdarg (XmNbottomPosition, (i + 1) * MAX_LAYER);
01620               stdarg (XmNlabelString, XmStringCreatePCB (" "));
01621               stdarg (XmNspacing, 0);
01622               stdarg (XmNvisibleWhenOff, True);
01623               stdarg (XmNfillOnSelect, True);
01624               stdarg (XmNshadowThickness, 0);
01625               stdarg (XmNmarginWidth, 0);
01626               stdarg (XmNmarginHeight, 0);
01627               stdarg (XmNhighlightThickness, 0);
01628               lgbuttons[i][j] =
01629                 XmCreateToggleButton (lg_buttonform, "label", args, n);
01630               XtManageChild (lgbuttons[i][j]);
01631 
01632               XtAddCallback (lgbuttons[i][j], XmNvalueChangedCallback,
01633                              (XtCallbackProc) lgbutton_cb,
01634                              (XtPointer) (i * max_group + j));
01635             }
01636         }
01637 #endif
01638     }
01639   lesstif_update_layer_groups ();
01640   XtManageChild (layer_groups_form);
01641   return 1;
01642 }
01643 
01644 /* ------------------------------------------------------------ */
01645 
01646 typedef struct {
01647   Widget del;
01648   Widget w_name;
01649   Widget w_value;
01650 } AttrRow;
01651 
01652 static AttrRow *attr_row = 0;
01653 static int attr_num_rows = 0;
01654 static int attr_max_rows = 0;
01655 static Widget attr_dialog = NULL, f_top;
01656 static AttributeListType *attributes_list;
01657 
01658 static void attributes_delete_callback (Widget w, void *v, void *cbs);
01659 
01660 static void
01661 fiddle_with_bb_layout ()
01662 {
01663   int i;
01664   int max_height = 0;
01665   int max_del_width = 0;
01666   int max_name_width = 0;
01667   int max_value_width = 0;
01668   short ncolumns = 20;
01669   short vcolumns = 20;
01670 
01671   for (i=0; i<attr_num_rows; i++)
01672     {
01673       String v;
01674 
01675       n = 0;
01676       stdarg (XmNvalue, &v);
01677       XtGetValues (attr_row[i].w_name, args, n);
01678       if (ncolumns < strlen (v))
01679         ncolumns = strlen (v);
01680 
01681       n = 0;
01682       stdarg (XmNvalue, &v);
01683       XtGetValues (attr_row[i].w_value, args, n);
01684       if (vcolumns < strlen (v))
01685         vcolumns = strlen (v);
01686     }
01687 
01688   for (i=0; i<attr_num_rows; i++)
01689     {
01690       n = 0;
01691       stdarg (XmNcolumns, ncolumns);
01692       XtSetValues (attr_row[i].w_name, args, n);
01693 
01694       n = 0;
01695       stdarg (XmNcolumns, vcolumns);
01696       XtSetValues (attr_row[i].w_value, args, n);
01697     }
01698 
01699   for (i=0; i<attr_num_rows; i++)
01700     {
01701       Dimension w, h;
01702       n = 0;
01703       stdarg (XmNwidth, &w);
01704       stdarg (XmNheight, &h);
01705 
01706       XtGetValues (attr_row[i].del, args, n);
01707       if (max_height < h)
01708         max_height = h;
01709       if (max_del_width < w)
01710         max_del_width = w;
01711 
01712       XtGetValues (attr_row[i].w_name, args, n);
01713       if (max_height < h)
01714         max_height = h;
01715       if (max_name_width < w)
01716         max_name_width = w;
01717 
01718       XtGetValues (attr_row[i].w_value, args, n);
01719       if (max_height < h)
01720         max_height = h;
01721       if (max_value_width < w)
01722         max_value_width = w;
01723     }
01724 
01725   for (i=0; i<attr_num_rows; i++)
01726     {
01727       n = 0;
01728       stdarg (XmNx, 0);
01729       stdarg (XmNy, i * max_height);
01730       stdarg (XmNwidth, max_del_width);
01731       stdarg (XmNheight, max_height);
01732       XtSetValues (attr_row[i].del, args, n);
01733 
01734       n = 0;
01735       stdarg (XmNx, max_del_width);
01736       stdarg (XmNy, i * max_height);
01737       stdarg (XmNwidth, max_name_width);
01738       stdarg (XmNheight, max_height);
01739       XtSetValues (attr_row[i].w_name, args, n);
01740 
01741       n = 0;
01742       stdarg (XmNx, max_del_width + max_name_width);
01743       stdarg (XmNy, i * max_height);
01744       stdarg (XmNwidth, max_value_width);
01745       stdarg (XmNheight, max_height);
01746       XtSetValues (attr_row[i].w_value, args, n);
01747     }
01748 
01749   n = 0;
01750   stdarg (XmNwidth, max_del_width + max_name_width + max_value_width + 1);
01751   stdarg (XmNheight, max_height * attr_num_rows + 1);
01752   XtSetValues (f_top, args, n);
01753 }
01754 
01755 static void
01756 lesstif_attributes_need_rows (int new_max)
01757 {
01758   if (attr_max_rows < new_max)
01759     {
01760       if (attr_row)
01761         attr_row = (AttrRow *) realloc (attr_row, new_max * sizeof(AttrRow));
01762       else
01763         attr_row = (AttrRow *) malloc (new_max * sizeof(AttrRow));
01764     }
01765 
01766   while (attr_max_rows < new_max)
01767     {
01768       n = 0;
01769       attr_row[attr_max_rows].del = XmCreatePushButton (f_top, "del", args, n);
01770       XtManageChild (attr_row[attr_max_rows].del);
01771       XtAddCallback (attr_row[attr_max_rows].del, XmNactivateCallback,
01772                      (XtCallbackProc) attributes_delete_callback,
01773                      (XtPointer) (size_t) attr_max_rows);
01774 
01775       n = 0;
01776       stdarg (XmNresizeWidth, True);
01777       attr_row[attr_max_rows].w_name = XmCreateTextField (f_top, "name", args, n);
01778       XtManageChild (attr_row[attr_max_rows].w_name);
01779       XtAddCallback (attr_row[attr_max_rows].w_name, XmNvalueChangedCallback,
01780                      (XtCallbackProc) fiddle_with_bb_layout, NULL);
01781 
01782       n = 0;
01783       stdarg (XmNresizeWidth, True);
01784       attr_row[attr_max_rows].w_value = XmCreateTextField (f_top, "value", args, n);
01785       XtManageChild (attr_row[attr_max_rows].w_value);
01786       XtAddCallback (attr_row[attr_max_rows].w_value, XmNvalueChangedCallback,
01787                      (XtCallbackProc) fiddle_with_bb_layout, NULL);
01788 
01789       attr_max_rows ++;
01790     }
01791 
01792   /* Manage any previously unused rows we now need to show.  */
01793   while (attr_num_rows < new_max)
01794     {
01795       XtManageChild (attr_row[attr_num_rows].del);
01796       XtManageChild (attr_row[attr_num_rows].w_name);
01797       XtManageChild (attr_row[attr_num_rows].w_value);
01798       attr_num_rows ++;
01799     }
01800 }
01801 
01802 static void
01803 lesstif_attributes_revert ()
01804 {
01805   int i;
01806 
01807   lesstif_attributes_need_rows (attributes_list->Number);
01808 
01809   /* Unmanage any previously used rows we don't need.  */
01810   while (attr_num_rows > attributes_list->Number)
01811     {
01812       attr_num_rows --;
01813       XtUnmanageChild (attr_row[attr_num_rows].del);
01814       XtUnmanageChild (attr_row[attr_num_rows].w_name);
01815       XtUnmanageChild (attr_row[attr_num_rows].w_value);
01816     }
01817 
01818   /* Fill in values */
01819   for (i=0; i<attributes_list->Number; i++)
01820     {
01821       XmTextFieldSetString (attr_row[i].w_name, attributes_list->List[i].name);
01822       XmTextFieldSetString (attr_row[i].w_value, attributes_list->List[i].value);
01823     }
01824 
01825   fiddle_with_bb_layout ();
01826 }
01827 
01828 static void
01829 attributes_new_callback (Widget w, void *v, void *cbs)
01830 {
01831   lesstif_attributes_need_rows (attr_num_rows + 1); /* also bumps attr_num_rows */
01832   XmTextFieldSetString (attr_row[attr_num_rows-1].w_name, "");
01833   XmTextFieldSetString (attr_row[attr_num_rows-1].w_value, "");
01834 
01835   fiddle_with_bb_layout ();
01836 }
01837 
01838 static void
01839 attributes_delete_callback (Widget w, void *v, void *cbs)
01840 {
01841   int i, n;
01842   Widget wn, wv;
01843 
01844   n = (int) (size_t) v;
01845 
01846   wn = attr_row[n].w_name;
01847   wv = attr_row[n].w_value;
01848 
01849   for (i=n; i<attr_num_rows-1; i++)
01850     {
01851       attr_row[i].w_name = attr_row[i+1].w_name;
01852       attr_row[i].w_value = attr_row[i+1].w_value;
01853     }
01854   attr_row[attr_num_rows-1].w_name = wn;
01855   attr_row[attr_num_rows-1].w_value = wv;
01856   attr_num_rows --;
01857 
01858   XtUnmanageChild (wn);
01859   XtUnmanageChild (wv);
01860 
01861   fiddle_with_bb_layout ();
01862 }
01863 
01864 static void
01865 attributes_revert_callback (Widget w, void *v, void *cbs)
01866 {
01867   lesstif_attributes_revert ();
01868 }
01869 
01870 void
01871 lesstif_attributes_dialog (char *owner, AttributeListType *attrs_list)
01872 {
01873   Widget bform, sw, b_ok, b_cancel, b_revert, b_new;
01874   Widget sep;
01875 
01876   if (attr_dialog == NULL)
01877     {
01878       n = 0;
01879       stdarg (XmNautoUnmanage, False);
01880       stdarg (XmNtitle, owner);
01881       stdarg (XmNwidth, 400);
01882       stdarg (XmNheight, 300);
01883       attr_dialog = XmCreateFormDialog (mainwind, "attributes", args, n);
01884 
01885       n = 0;
01886       stdarg (XmNrightAttachment, XmATTACH_FORM);
01887       stdarg (XmNbottomAttachment, XmATTACH_FORM);
01888       stdarg (XmNorientation, XmHORIZONTAL);
01889       stdarg (XmNentryAlignment, XmALIGNMENT_CENTER);
01890       stdarg (XmNpacking, XmPACK_COLUMN);
01891       bform = XmCreateRowColumn (attr_dialog, "attributes", args, n);
01892       XtManageChild (bform);
01893 
01894       n = 0;
01895       b_ok = XmCreatePushButton (bform, "OK", args, n);
01896       XtManageChild (b_ok);
01897       XtAddCallback (b_ok, XmNactivateCallback,
01898                      (XtCallbackProc) dialog_callback,
01899                      (XtPointer) 0);
01900 
01901       n = 0;
01902       b_new = XmCreatePushButton (bform, "New", args, n);
01903       XtManageChild (b_new);
01904       XtAddCallback (b_new, XmNactivateCallback,
01905                      (XtCallbackProc) attributes_new_callback,
01906                      NULL);
01907 
01908       n = 0;
01909       b_revert = XmCreatePushButton (bform, "Revert", args, n);
01910       XtManageChild (b_revert);
01911       XtAddCallback (b_revert, XmNactivateCallback,
01912                      (XtCallbackProc) attributes_revert_callback,
01913                      NULL);
01914 
01915       n = 0;
01916       b_cancel = XmCreatePushButton (bform, "Cancel", args, n);
01917       XtManageChild (b_cancel);
01918       XtAddCallback (b_cancel, XmNactivateCallback,
01919                      (XtCallbackProc) dialog_callback,
01920                      (XtPointer) 1);
01921 
01922       n = 0;
01923       stdarg (XmNleftAttachment, XmATTACH_FORM);
01924       stdarg (XmNrightAttachment, XmATTACH_FORM);
01925       stdarg (XmNbottomAttachment, XmATTACH_WIDGET);
01926       stdarg (XmNbottomWidget, bform);
01927       sep = XmCreateSeparator (attr_dialog, "attributes", args, n);
01928       XtManageChild (sep);
01929 
01930       n = 0;
01931       stdarg (XmNtopAttachment, XmATTACH_FORM);
01932       stdarg (XmNleftAttachment, XmATTACH_FORM);
01933       stdarg (XmNrightAttachment, XmATTACH_FORM);
01934       stdarg (XmNbottomAttachment, XmATTACH_WIDGET);
01935       stdarg (XmNbottomWidget, sep);
01936       stdarg (XmNscrollingPolicy, XmAUTOMATIC);
01937       sw = XmCreateScrolledWindow (attr_dialog, "attributes", args, n);
01938       XtManageChild (sw);
01939 
01940       n = 0;
01941       stdarg (XmNmarginHeight, 0);
01942       stdarg (XmNmarginWidth, 0);
01943       f_top = XmCreateBulletinBoard (sw, "f_top", args, n);
01944       XtManageChild (f_top);
01945     }
01946   else
01947     {
01948       n = 0;
01949       stdarg (XmNtitle, owner);
01950       XtSetValues (XtParent (attr_dialog), args, n);
01951     }
01952 
01953   attributes_list = attrs_list;
01954   lesstif_attributes_revert ();
01955 
01956   fiddle_with_bb_layout ();
01957 
01958   if (wait_for_dialog (attr_dialog) == 0)
01959     {
01960       int i;
01961       /* Copy the values back */
01962       for (i=0; i<attributes_list->Number; i++)
01963         {
01964           if (attributes_list->List[i].name)
01965             free (attributes_list->List[i].name);
01966           if (attributes_list->List[i].value)
01967             free (attributes_list->List[i].value);
01968         }
01969       if (attributes_list->Max < attr_num_rows)
01970         {
01971           int sz = attr_num_rows * sizeof (AttributeType);
01972           if (attributes_list->List == NULL)
01973             attributes_list->List = (AttributeType *) malloc (sz);
01974           else
01975             attributes_list->List = (AttributeType *) realloc (attributes_list->List, sz);
01976           attributes_list->Max = attr_num_rows;
01977         }
01978       for (i=0; i<attr_num_rows; i++)
01979         {
01980           attributes_list->List[i].name = strdup (XmTextFieldGetString (attr_row[i].w_name));
01981           attributes_list->List[i].value = strdup (XmTextFieldGetString (attr_row[i].w_value));
01982           attributes_list->Number = attr_num_rows;
01983         }
01984     }
01985 
01986   return;
01987 }
01988 
01989 /* ------------------------------------------------------------ */
01990 
01991 static const char importgui_syntax[] =
01992 "ImportGUI()";
01993 
01994 static const char importgui_help[] =
01995 "Lets the user choose the schematics to import from";
01996 
01997 /* %start-doc actions ImportGUI
01998 
01999 Displays a dialog that lets the user select the schematic(s) to import
02000 from, then saves that information in the layout's attributes for
02001 future imports.
02002 
02003 %end-doc */
02004 
02005 static int
02006 ImportGUI (int argc, char **argv, Coord x, Coord y)
02007 {
02008   static int I_am_recursing = 0;
02009   static XmString xms_sch = 0, xms_import = 0;
02010   int rv;
02011   XmString xmname;
02012   char *name, *bname;
02013   char *original_dir, *target_dir, *last_slash;
02014 
02015   if (I_am_recursing)
02016     return 1;
02017 
02018   if (xms_sch == 0)
02019     xms_sch = XmStringCreatePCB ("*.sch");
02020   if (xms_import == 0)
02021     xms_import = XmStringCreatePCB ("Import from");
02022 
02023   setup_fsb_dialog ();
02024 
02025   n = 0;
02026   stdarg (XmNtitle, "Import From");
02027   XtSetValues (XtParent (fsb), args, n);
02028 
02029   n = 0;
02030   stdarg (XmNpattern, xms_sch);
02031   stdarg (XmNmustMatch, True);
02032   stdarg (XmNselectionLabelString, xms_import);
02033   XtSetValues (fsb, args, n);
02034 
02035   n = 0;
02036   stdarg (XmNdirectory, &xmname);
02037   XtGetValues (fsb, args, n);
02038   XmStringGetLtoR (xmname, XmFONTLIST_DEFAULT_TAG, &original_dir);
02039 
02040   if (!wait_for_dialog (fsb))
02041     return 1;
02042 
02043   n = 0;
02044   stdarg (XmNdirectory, &xmname);
02045   XtGetValues (fsb, args, n);
02046   XmStringGetLtoR (xmname, XmFONTLIST_DEFAULT_TAG, &target_dir);
02047 
02048   n = 0;
02049   stdarg (XmNdirSpec, &xmname);
02050   XtGetValues (fsb, args, n);
02051 
02052   XmStringGetLtoR (xmname, XmFONTLIST_DEFAULT_TAG, &name);
02053 
02054   /* If the user didn't change directories, use just the base name.
02055      This is the common case and means we don't have to get clever
02056      about converting absolute paths into relative paths.  */
02057   bname = name;
02058   if (strcmp (original_dir, target_dir) == 0)
02059     {
02060       last_slash = strrchr (name, '/');
02061       if (last_slash)
02062         bname = last_slash + 1;
02063     }
02064 
02065   AttributePut (PCB, "import::src0", bname);
02066 
02067   XtFree (name);
02068 
02069 
02070   I_am_recursing = 1;
02071   rv = hid_action ("Import");
02072   I_am_recursing = 0;
02073 
02074   return rv;
02075 }
02076 
02077 /* ------------------------------------------------------------ */
02078 
02079 HID_Action lesstif_dialog_action_list[] = {
02080   {"Load", 0, Load,
02081    load_help, load_syntax},
02082   {"LoadVendor", 0, LoadVendor,
02083    loadvendor_help, loadvendor_syntax},
02084   {"Save", 0, Save,
02085    save_help, save_syntax},
02086   {"DoWindows", 0, DoWindows,
02087    dowindows_help, dowindows_syntax},
02088   {"PromptFor", 0, PromptFor,
02089    promptfor_help, promptfor_syntax},
02090   {"Confirm", 0, ConfirmAction},
02091   {"About", 0, About,
02092    about_help, about_syntax},
02093   {"Print", 0, Print,
02094    print_help, print_syntax},
02095   {"PrintCalibrate", 0, PrintCalibrate,
02096    printcalibrate_help, printcalibrate_syntax},
02097   {"Export", 0, Export,
02098    export_help, export_syntax},
02099   {"AdjustSizes", 0, AdjustSizes,
02100    adjustsizes_help, adjustsizes_syntax},
02101   {"EditLayerGroups", 0, EditLayerGroups,
02102    editlayergroups_help, editlayergroups_syntax},
02103   {"ImportGUI", 0, ImportGUI,
02104    importgui_help, importgui_syntax},
02105 };
02106 
02107 REGISTER_ACTIONS (lesstif_dialog_action_list)