select.c: Remove Draw() call from SelectConnection
[geda-pcb/leaky.git] / src / hid / lesstif / menu.c
blob6baa016af264d87d28af64664da19bcb0fd2208a
1 //* $Id$ */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <ctype.h>
11 #include <unistd.h>
13 #include "xincludes.h"
15 #include "global.h"
16 #include "data.h"
17 #include "error.h"
18 #include "misc.h"
20 #include "hid.h"
21 #include "../hidint.h"
22 #include "hid/common/hid_resource.h"
23 #include "resource.h"
24 #include "lesstif.h"
25 #include "mymem.h"
27 #include "pcb-menu.h"
29 #ifdef HAVE_LIBDMALLOC
30 #include <dmalloc.h>
31 #endif
33 RCSID ("$Id$");
35 #ifndef R_OK
36 /* Common value for systems that don't define it. */
37 #define R_OK 4
38 #endif
40 Display *display;
41 static Colormap cmap;
43 static Arg args[30];
44 static int n;
45 #define stdarg(t,v) XtSetArg(args[n], t, v), n++
47 static void note_accelerator (char *acc, Resource * node);
48 static void note_widget_flag (Widget w, char *type, char *name);
50 static const char getxy_syntax[] =
51 "GetXY()";
53 static const char getxy_help[] =
54 "Get a coordinate.";
56 /* %start-doc actions GetXY
58 Prompts the user for a coordinate, if one is not already selected.
60 %end-doc */
62 static int
63 GetXY (int argc, char **argv, int x, int y)
65 return 0;
68 static const char debug_syntax[] =
69 "Debug(...)";
71 static const char debug_help[] =
72 "Debug action.";
74 /* %start-doc actions Debug
76 This action exists to help debug scripts; it simply prints all its
77 arguments to stdout.
79 %end-doc */
81 static const char debugxy_syntax[] =
82 "DebugXY(...)";
84 static const char debugxy_help[] =
85 "Debug action, with coordinates";
87 /* %start-doc actions DebugXY
89 Like @code{Debug}, but requires a coordinate. If the user hasn't yet
90 indicated a location on the board, the user will be prompted to click
91 on one.
93 %end-doc */
95 static int
96 Debug (int argc, char **argv, int x, int y)
98 int i;
99 printf ("Debug:");
100 for (i = 0; i < argc; i++)
101 printf (" [%d] `%s'", i, argv[i]);
102 printf (" x,y %d,%d\n", x, y);
103 return 0;
106 static const char return_syntax[] =
107 "Return(0|1)";
109 static const char return_help[] =
110 "Simulate a passing or failing action.";
112 /* %start-doc actions Return
114 This is for testing. If passed a 0, does nothing and succeeds. If
115 passed a 1, does nothing but pretends to fail.
117 %end-doc */
119 static int
120 Return (int argc, char **argv, int x, int y)
122 return atoi (argv[0]);
125 static const char dumpkeys_syntax[] =
126 "DumpKeys()";
128 static const char dumpkeys_help[] =
129 "Dump Lesstif key bindings.";
131 /* %start-doc actions DumpKeys
133 Causes the list of key bindings (from @code{pcb-menu.res}) to be
134 dumped to stdout. This is most useful when invoked from the command
135 line like this:
137 @example
138 pcb --action-string DumpKeys
139 @end example
141 %end-doc */
143 static int do_dump_keys = 0;
144 static int
145 DumpKeys (int argc, char **argv, int x, int y)
147 do_dump_keys = 1;
148 return 0;
151 /*-----------------------------------------------------------------------------*/
153 #define LB_SILK (MAX_LAYER+0)
154 #define LB_RATS (MAX_LAYER+1)
155 #define LB_NUMPICK (LB_RATS+1)
156 /* more */
157 #define LB_PINS (MAX_LAYER+2)
158 #define LB_VIAS (MAX_LAYER+3)
159 #define LB_BACK (MAX_LAYER+4)
160 #define LB_MASK (MAX_LAYER+5)
161 #define LB_NUM (MAX_LAYER+6)
163 typedef struct
165 Widget w[LB_NUM];
166 int is_pick;
167 } LayerButtons;
169 static LayerButtons *layer_button_list = 0;
170 static int num_layer_buttons = 0;
171 static int fg_colors[LB_NUM];
172 static int bg_color;
174 extern Widget lesstif_m_layer;
176 static int
177 LayersChanged (int argc, char **argv, int x, int y)
179 int l, i, set;
180 char *name;
181 int current_layer;
183 if (!layer_button_list)
184 return 0;
185 if (PCB && PCB->Data)
187 DataType *d = PCB->Data;
188 for (i = 0; i < MAX_LAYER; i++)
189 fg_colors[i] = lesstif_parse_color (d->Layer[i].Color);
190 fg_colors[LB_SILK] = lesstif_parse_color (PCB->ElementColor);
191 fg_colors[LB_RATS] = lesstif_parse_color (PCB->RatColor);
192 fg_colors[LB_PINS] = lesstif_parse_color (PCB->PinColor);
193 fg_colors[LB_VIAS] = lesstif_parse_color (PCB->ViaColor);
194 fg_colors[LB_BACK] =
195 lesstif_parse_color (PCB->InvisibleObjectsColor);
196 fg_colors[LB_MASK] = lesstif_parse_color (PCB->MaskColor);
197 bg_color = lesstif_parse_color (Settings.BackgroundColor);
199 else
201 for (i = 0; i < MAX_LAYER; i++)
202 fg_colors[i] = lesstif_parse_color (Settings.LayerColor[i]);
203 fg_colors[LB_SILK] = lesstif_parse_color (Settings.ElementColor);
204 fg_colors[LB_RATS] = lesstif_parse_color (Settings.RatColor);
205 fg_colors[LB_PINS] = lesstif_parse_color (Settings.PinColor);
206 fg_colors[LB_VIAS] = lesstif_parse_color (Settings.ViaColor);
207 fg_colors[LB_BACK] =
208 lesstif_parse_color (Settings.InvisibleObjectsColor);
209 fg_colors[LB_MASK] = lesstif_parse_color (Settings.MaskColor);
210 bg_color = lesstif_parse_color (Settings.BackgroundColor);
213 if (PCB->RatDraw)
214 current_layer = LB_RATS;
215 else if (PCB->SilkActive)
216 current_layer = LB_SILK;
217 else
218 current_layer = LayerStack[0];
220 for (l = 0; l < num_layer_buttons; l++)
222 LayerButtons *lb = layer_button_list + l;
223 for (i = 0; i < (lb->is_pick ? LB_NUMPICK : LB_NUM); i++)
225 switch (i)
227 case LB_SILK:
228 set = PCB->ElementOn;
229 break;
230 case LB_RATS:
231 set = PCB->RatOn;
232 break;
233 case LB_PINS:
234 set = PCB->PinOn;
235 break;
236 case LB_VIAS:
237 set = PCB->ViaOn;
238 break;
239 case LB_BACK:
240 set = PCB->InvisibleObjectsOn;
241 break;
242 case LB_MASK:
243 set = TEST_FLAG (SHOWMASKFLAG, PCB);
244 break;
245 default: /* layers */
246 set = PCB->Data->Layer[i].On;
247 break;
250 n = 0;
251 if (i < MAX_LAYER && PCB->Data->Layer[i].Name)
253 XmString s = XmStringCreateLocalized (PCB->Data->Layer[i].Name);
254 stdarg (XmNlabelString, s);
256 if (!lb->is_pick)
258 if (set)
260 stdarg (XmNforeground, bg_color);
261 stdarg (XmNbackground, fg_colors[i]);
263 else
265 stdarg (XmNforeground, fg_colors[i]);
266 stdarg (XmNbackground, bg_color);
268 stdarg (XmNset, set);
270 else
272 stdarg (XmNforeground, bg_color);
273 stdarg (XmNbackground, fg_colors[i]);
274 stdarg (XmNset, current_layer == i ? True : False);
276 XtSetValues (lb->w[i], args, n);
278 if (i >= max_copper_layer && i < MAX_LAYER)
279 XtUnmanageChild(lb->w[i]);
280 else
281 XtManageChild(lb->w[i]);
284 if (lesstif_m_layer)
286 switch (current_layer)
288 case LB_RATS:
289 name = "Rats";
290 break;
291 case LB_SILK:
292 name = "Silk";
293 break;
294 default:
295 name = PCB->Data->Layer[current_layer].Name;
296 break;
298 n = 0;
299 stdarg (XmNbackground, fg_colors[current_layer]);
300 stdarg (XmNforeground, bg_color);
301 stdarg (XmNlabelString, XmStringCreateLocalized (name));
302 XtSetValues (lesstif_m_layer, args, n);
305 lesstif_update_layer_groups ();
307 return 0;
310 static void
311 show_one_layer_button (int layer, int set)
313 int l;
314 n = 0;
315 if (set)
317 stdarg (XmNforeground, bg_color);
318 stdarg (XmNbackground, fg_colors[layer]);
320 else
322 stdarg (XmNforeground, fg_colors[layer]);
323 stdarg (XmNbackground, bg_color);
325 stdarg (XmNset, set);
327 for (l = 0; l < num_layer_buttons; l++)
329 LayerButtons *lb = layer_button_list + l;
330 if (!lb->is_pick)
331 XtSetValues (lb->w[layer], args, n);
335 static void
336 layer_button_callback (Widget w, int layer, XmPushButtonCallbackStruct * pbcs)
338 int l, set;
339 switch (layer)
341 case LB_SILK:
342 set = PCB->ElementOn = !PCB->ElementOn;
343 PCB->Data->SILKLAYER.On = set;
344 PCB->Data->BACKSILKLAYER.On = set;
345 break;
346 case LB_RATS:
347 set = PCB->RatOn = !PCB->RatOn;
348 break;
349 case LB_PINS:
350 set = PCB->PinOn = !PCB->PinOn;
351 break;
352 case LB_VIAS:
353 set = PCB->ViaOn = !PCB->ViaOn;
354 break;
355 case LB_BACK:
356 set = PCB->InvisibleObjectsOn = !PCB->InvisibleObjectsOn;
357 break;
358 case LB_MASK:
359 TOGGLE_FLAG (SHOWMASKFLAG, PCB);
360 set = TEST_FLAG (SHOWMASKFLAG, PCB);
361 break;
362 default: /* layers */
363 set = PCB->Data->Layer[layer].On = !PCB->Data->Layer[layer].On;
364 break;
367 show_one_layer_button (layer, set);
368 if (layer < max_copper_layer)
370 int i;
371 int group = GetLayerGroupNumberByNumber (layer);
372 for (i = 0; i < PCB->LayerGroups.Number[group]; i++)
374 l = PCB->LayerGroups.Entries[group][i];
375 if (l != layer && l < max_copper_layer)
377 show_one_layer_button (l, set);
378 PCB->Data->Layer[l].On = set;
382 lesstif_invalidate_all ();
385 static void
386 layerpick_button_callback (Widget w, int layer,
387 XmPushButtonCallbackStruct * pbcs)
389 int l, i;
390 char *name;
391 PCB->RatDraw = (layer == LB_RATS);
392 PCB->SilkActive = (layer == LB_SILK);
393 if (layer < max_copper_layer)
394 ChangeGroupVisibility (layer, 1, 1);
395 for (l = 0; l < num_layer_buttons; l++)
397 LayerButtons *lb = layer_button_list + l;
398 if (!lb->is_pick)
399 continue;
400 for (i = 0; i < LB_NUMPICK; i++)
401 XmToggleButtonSetState (lb->w[i], layer == i, False);
403 switch (layer)
405 case LB_RATS:
406 name = "Rats";
407 break;
408 case LB_SILK:
409 name = "Silk";
410 break;
411 default:
412 name = PCB->Data->Layer[layer].Name;
413 break;
415 n = 0;
416 stdarg (XmNbackground, fg_colors[layer]);
417 stdarg (XmNforeground, bg_color);
418 stdarg (XmNlabelString, XmStringCreateLocalized (name));
419 XtSetValues (lesstif_m_layer, args, n);
420 lesstif_invalidate_all ();
423 static const char selectlayer_syntax[] =
424 "SelectLayer(1..MAXLAYER|Silk|Rats)";
426 static const char selectlayer_help[] =
427 "Select which layer is the current layer.";
429 /* %start-doc actions SelectLayer
431 The specified layer becomes the currently active layer. It is made
432 visible if it is not already visible
434 %end-doc */
436 static int
437 SelectLayer (int argc, char **argv, int x, int y)
439 int newl;
440 if (argc == 0)
441 return 1;
442 if (strcasecmp (argv[0], "silk") == 0)
443 newl = LB_SILK;
444 else if (strcasecmp (argv[0], "rats") == 0)
445 newl = LB_RATS;
446 else
447 newl = atoi (argv[0]) - 1;
448 layerpick_button_callback (0, newl, 0);
449 return 0;
452 static const char toggleview_syntax[] =
453 "ToggleView(1..MAXLAYER)\n"
454 "ToggleView(layername)\n"
455 "ToggleView(Silk|Rats|Pins|Vias|Mask|BackSide)";
457 static const char toggleview_help[] =
458 "Toggle the visibility of the specified layer or layer group.";
460 /* %start-doc actions ToggleView
462 If you pass an integer, that layer is specified by index (the first
463 layer is @code{1}, etc). If you pass a layer name, that layer is
464 specified by name. When a layer is specified, the visibility of the
465 layer group containing that layer is toggled.
467 If you pass a special layer name, the visibility of those components
468 (silk, rats, etc) is toggled. Note that if you have a layer named
469 the same as a special layer, the layer is chosen over the special layer.
471 %end-doc */
473 static int
474 ToggleView (int argc, char **argv, int x, int y)
476 int i, l;
478 if (argc == 0)
479 return 1;
480 if (isdigit ((int) argv[0][0]))
482 l = atoi (argv[0]) - 1;
483 layer_button_callback (0, l, 0);
485 else if (strcmp (argv[0], "Silk") == 0)
486 layer_button_callback (0, LB_SILK, 0);
487 else if (strcmp (argv[0], "Rats") == 0)
488 layer_button_callback (0, LB_RATS, 0);
489 else if (strcmp (argv[0], "Pins") == 0)
490 layer_button_callback (0, LB_PINS, 0);
491 else if (strcmp (argv[0], "Vias") == 0)
492 layer_button_callback (0, LB_VIAS, 0);
493 else if (strcmp (argv[0], "Mask") == 0)
494 layer_button_callback (0, LB_MASK, 0);
495 else if (strcmp (argv[0], "BackSide") == 0)
496 layer_button_callback (0, LB_BACK, 0);
497 else
499 l = -1;
500 for (i = 0; i < max_copper_layer + 2; i++)
501 if (strcmp (argv[0], PCB->Data->Layer[i].Name) == 0)
503 l = i;
504 break;
506 if (l == -1)
507 return 1;
508 layer_button_callback (0, l, 0);
510 return 0;
513 static void
514 insert_layerview_buttons (Widget menu)
516 int i, s;
517 LayerButtons *lb;
519 num_layer_buttons++;
520 s = num_layer_buttons * sizeof (LayerButtons);
521 if (layer_button_list)
522 layer_button_list = (LayerButtons *) realloc (layer_button_list, s);
523 else
524 layer_button_list = (LayerButtons *) malloc (s);
525 lb = layer_button_list + num_layer_buttons - 1;
527 for (i = 0; i < LB_NUM; i++)
529 static char namestr[] = "Label ";
530 char *name = namestr;
531 Widget btn;
532 name[5] = 'A' + i;
533 switch (i)
535 case LB_SILK:
536 name = "Silk";
537 break;
538 case LB_RATS:
539 name = "Rat Lines";
540 break;
541 case LB_PINS:
542 name = "Pins/Pads";
543 break;
544 case LB_VIAS:
545 name = "Vias";
546 break;
547 case LB_BACK:
548 name = "Far Side";
549 break;
550 case LB_MASK:
551 name = "Solder Mask";
552 break;
554 n = 0;
555 if (i < MAX_LAYER && i < 9)
557 char buf[20], av[30];
558 Resource *ar;
559 XmString as;
560 sprintf (buf, "Ctrl-%d", i + 1);
561 as = XmStringCreateLocalized (buf);
562 stdarg (XmNacceleratorText, as);
563 ar = resource_create (0);
564 sprintf (av, "ToggleView(%d)", i + 1);
565 resource_add_val (ar, 0, strdup (av), 0);
566 resource_add_val (ar, 0, strdup (av), 0);
567 ar->flags |= FLAG_V;
568 sprintf (av, "Ctrl<Key>%d", i + 1);
569 note_accelerator (av, ar);
570 stdarg (XmNmnemonic, i + '1');
572 btn = XmCreateToggleButton (menu, name, args, n);
573 XtManageChild (btn);
574 XtAddCallback (btn, XmNvalueChangedCallback,
575 (XtCallbackProc) layer_button_callback, (XtPointer) (size_t) i);
576 lb->w[i] = btn;
578 if (i == LB_MASK)
579 note_widget_flag (btn, XmNset, "showmask");
581 lb->is_pick = 0;
582 LayersChanged (0, 0, 0, 0);
585 static void
586 insert_layerpick_buttons (Widget menu)
588 int i, s;
589 LayerButtons *lb;
591 num_layer_buttons++;
592 s = num_layer_buttons * sizeof (LayerButtons);
593 if (layer_button_list)
594 layer_button_list = (LayerButtons *) realloc (layer_button_list, s);
595 else
596 layer_button_list = (LayerButtons *) malloc (s);
597 lb = layer_button_list + num_layer_buttons - 1;
599 for (i = 0; i < LB_NUMPICK; i++)
601 static char namestr[] = "Label ";
602 char *name = namestr;
603 Widget btn;
604 name[5] = 'A' + i;
605 switch (i)
607 case LB_SILK:
608 name = "Silk";
609 break;
610 case LB_RATS:
611 name = "Rat Lines";
612 break;
614 n = 0;
615 if (i < MAX_LAYER && i < 9)
617 char buf[20], av[30];
618 Resource *ar;
619 XmString as;
620 sprintf (buf, "%d", i + 1);
621 as = XmStringCreateLocalized (buf);
622 stdarg (XmNacceleratorText, as);
623 ar = resource_create (0);
624 switch (i)
626 case LB_SILK:
627 strcpy (av, "SelectLayer(Silk)");
628 break;
629 case LB_RATS:
630 strcpy (av, "SelectLayer(Rats)");
631 break;
632 default:
633 sprintf (av, "SelectLayer(%d)", i + 1);
634 break;
636 resource_add_val (ar, 0, strdup (av), 0);
637 resource_add_val (ar, 0, strdup (av), 0);
638 ar->flags |= FLAG_V;
639 sprintf (av, "<Key>%d", i + 1);
640 note_accelerator (av, ar);
641 stdarg (XmNmnemonic, i + '1');
643 stdarg (XmNindicatorType, XmONE_OF_MANY);
644 btn = XmCreateToggleButton (menu, name, args, n);
645 XtManageChild (btn);
646 XtAddCallback (btn, XmNvalueChangedCallback,
647 (XtCallbackProc) layerpick_button_callback,
648 (XtPointer) (size_t) i);
649 lb->w[i] = btn;
651 lb->is_pick = 1;
652 LayersChanged (0, 0, 0, 0);
655 /*-----------------------------------------------------------------------------*/
657 typedef struct
659 Widget w;
660 const char *flagname;
661 int oldval;
662 char *xres;
663 } WidgetFlagType;
665 static WidgetFlagType *wflags = 0;
666 static int n_wflags = 0;
667 static int max_wflags = 0;
669 static void
670 note_widget_flag (Widget w, char *type, char *name)
672 if (n_wflags >= max_wflags)
674 max_wflags += 20;
675 wflags = realloc (wflags, max_wflags * sizeof (WidgetFlagType));
677 wflags[n_wflags].w = w;
678 wflags[n_wflags].flagname = name;
679 wflags[n_wflags].oldval = -1;
680 wflags[n_wflags].xres = type;
681 n_wflags++;
684 void
685 lesstif_update_widget_flags ()
687 int i;
689 for (i = 0; i < n_wflags; i++)
691 int v = hid_get_flag (wflags[i].flagname);
692 Arg args[1];
693 XtSetArg (args[0], wflags[i].xres, v ? 1 : 0);
694 XtSetValues (wflags[i].w, args, 1);
695 wflags[i].oldval = v;
699 /*-----------------------------------------------------------------------------*/
701 HID_Action lesstif_menu_action_list[] = {
702 {"DumpKeys", 0, DumpKeys,
703 dumpkeys_help, dumpkeys_syntax},
704 {"Debug", 0, Debug,
705 debug_help, debug_syntax},
706 {"DebugXY", "Click X,Y for Debug", Debug,
707 debugxy_help, debugxy_syntax},
708 {"GetXY", "", GetXY,
709 getxy_help, getxy_syntax},
710 {"Return", 0, Return,
711 return_help, return_syntax},
712 {"LayersChanged", 0, LayersChanged,
713 layerschanged_help, layerschanged_syntax},
714 {"ToggleView", 0, ToggleView,
715 toggleview_help, toggleview_syntax},
716 {"SelectLayer", 0, SelectLayer,
717 selectlayer_help, selectlayer_syntax}
720 REGISTER_ACTIONS (lesstif_menu_action_list)
722 #if 0
723 static void
724 do_color (char *value, char *which)
726 XColor color;
727 if (XParseColor (display, cmap, value, &color))
728 if (XAllocColor (display, cmap, &color))
730 stdarg (which, color.pixel);
733 #endif
735 typedef struct ToggleItem
737 struct ToggleItem *next;
738 Widget w;
739 char *group, *item;
740 XtCallbackProc callback;
741 Resource *node;
742 } ToggleItem;
743 static ToggleItem *toggle_items = 0;
745 static int need_xy = 0, have_xy = 0, action_x, action_y;
747 static void
748 radio_callback (Widget toggle, ToggleItem * me,
749 XmToggleButtonCallbackStruct * cbs)
751 if (!cbs->set) /* uh uh, can't turn it off */
752 XmToggleButtonSetState (toggle, 1, 0);
753 else
755 ToggleItem *ti;
756 for (ti = toggle_items; ti; ti = ti->next)
757 if (strcmp (me->group, ti->group) == 0)
759 if (me->item == ti->item || strcmp (me->item, ti->item) == 0)
760 XmToggleButtonSetState (ti->w, 1, 0);
761 else
762 XmToggleButtonSetState (ti->w, 0, 0);
764 me->callback (toggle, me->node, cbs);
769 lesstif_button_event (Widget w, XEvent * e)
771 have_xy = 1;
772 action_x = e->xbutton.x;
773 action_y = e->xbutton.y;
774 if (!need_xy)
775 return 0;
776 if (w != work_area)
777 return 1;
778 return 0;
781 void
782 lesstif_get_xy (const char *message)
784 XmString ls = XmStringCreateLocalized ((char *)message);
786 XtManageChild (m_click);
787 n = 0;
788 stdarg (XmNlabelString, ls);
789 XtSetValues (m_click, args, n);
790 //printf("need xy: msg `%s'\n", msg);
791 need_xy = 1;
792 XBell (display, 100);
793 while (!have_xy)
795 XEvent e;
796 XtAppNextEvent (app_context, &e);
797 XtDispatchEvent (&e);
799 need_xy = 0;
800 have_xy = 1;
801 XtUnmanageChild (m_click);
804 void
805 lesstif_get_coords (const char *msg, int *px, int *py)
807 if (!have_xy && msg)
808 lesstif_get_xy (msg);
809 if (have_xy)
810 lesstif_coords_to_pcb (action_x, action_y, px, py);
813 static void
814 callback (Widget w, Resource * node, XmPushButtonCallbackStruct * pbcs)
816 int vi;
817 have_xy = 0;
818 lesstif_show_crosshair (0);
819 if (pbcs->event && pbcs->event->type == KeyPress)
821 Dimension wx, wy;
822 Widget aw = XtWindowToWidget (display, pbcs->event->xkey.window);
823 action_x = pbcs->event->xkey.x;
824 action_y = pbcs->event->xkey.y;
825 if (aw)
827 Widget p = work_area;
828 while (p && p != aw)
830 n = 0;
831 stdarg (XmNx, &wx);
832 stdarg (XmNy, &wy);
833 XtGetValues (p, args, n);
834 action_x -= wx;
835 action_y -= wy;
836 p = XtParent (p);
838 if (p == aw)
839 have_xy = 1;
841 //printf("have xy from %s: %d %d\n", XtName(aw), action_x, action_y);
844 lesstif_need_idle_proc ();
845 for (vi = 1; vi < node->c; vi++)
846 if (resource_type (node->v[vi]) == 10)
847 if (hid_parse_actions (node->v[vi].value))
848 return;
851 typedef struct acc_table_t
853 char mods;
854 char key_char;
855 union {
856 /* If M_Multi is set in mods, these are used to chain to the next
857 attribute table for multi-key accelerators. */
858 struct {
859 int n_chain;
860 struct acc_table_t *chain;
861 } c;
862 /* If M_Multi isn't set, these are used to map a single key to an
863 event. */
864 struct {
865 KeySym key;
866 Resource *node;
867 } a;
868 } u;
869 } acc_table_t;
871 static acc_table_t *acc_table;
872 static int acc_num = 0;
874 static int
875 acc_sort (const void *va, const void *vb)
877 acc_table_t *a = (acc_table_t *) va;
878 acc_table_t *b = (acc_table_t *) vb;
879 if (a->key_char != b->key_char)
880 return a->key_char - b->key_char;
881 if (!(a->mods & M_Multi))
882 if (a->u.a.key != b->u.a.key)
883 return a->u.a.key - b->u.a.key;
884 return a->mods - b->mods;
887 static int
888 DumpKeys2 ()
890 int i;
891 char ch[2];
892 printf ("in dumpkeys! %d\n", acc_num);
893 qsort (acc_table, acc_num, sizeof (acc_table_t), acc_sort);
894 ch[1] = 0;
895 for (i = 0; i < acc_num; i++)
897 char mod[16];
898 int vi;
899 char *tabs = "";
901 sprintf (mod, "%s%s%s",
902 acc_table[i].mods & M_Alt ? "Alt-" : "",
903 acc_table[i].mods & M_Ctrl ? "Ctrl-" : "",
904 acc_table[i].mods & M_Shift ? "Shift-" : "");
905 ch[0] = toupper ((int) acc_table[i].key_char);
906 printf ("%16s%s\t", mod,
907 acc_table[i].key_char ? ch : XKeysymToString (acc_table[i].
908 u.a.key));
910 for (vi = 1; vi < acc_table[i].u.a.node->c; vi++)
911 if (resource_type (acc_table[i].u.a.node->v[vi]) == 10)
913 printf ("%s%s", tabs, acc_table[i].u.a.node->v[vi].value);
914 tabs = "\n\t\t\t ";
917 printf ("\n");
919 exit (0);
922 static acc_table_t *
923 find_or_create_acc (char mods, char key, KeySym sym,
924 acc_table_t **table, int *n_ents)
926 int i, max;
927 acc_table_t *a;
929 if (*table)
930 for (i=(*n_ents)-1; i>=0; i--)
932 a = & (*table)[i];
933 if (a->mods == mods
934 && a->key_char == key
935 && (mods & M_Multi || a->u.a.key == sym))
936 return a;
939 (*n_ents) ++;
940 max = (*n_ents + 16) & ~15;
942 if (*table)
943 *table = (acc_table_t *) realloc (*table, max * sizeof (acc_table_t));
944 else
945 *table = (acc_table_t *) malloc (max * sizeof (acc_table_t));
947 a = & ((*table)[(*n_ents)-1]);
948 memset (a, 0, sizeof(acc_table_t));
950 a->mods = mods;
951 a->key_char = key;
952 if (!(mods & M_Multi))
953 a->u.a.key = sym;
955 return a;
958 static void
959 note_accelerator (char *acc, Resource * node)
961 char *orig_acc = acc;
962 int mods = 0;
963 acc_table_t *a;
964 char key_char = 0;
965 KeySym key = 0;
966 int multi_key = 0;
968 while (isalpha ((int) acc[0]))
970 if (strncmp (acc, "Shift", 5) == 0)
972 mods |= M_Shift;
973 acc += 5;
975 else if (strncmp (acc, "Ctrl", 4) == 0)
977 mods |= M_Ctrl;
978 acc += 4;
980 else if (strncmp (acc, "Alt", 3) == 0)
982 mods |= M_Alt;
983 acc += 3;
985 else
987 printf ("Must be Shift/Ctrl/Alt: %s\n", acc);
988 return;
990 while (*acc == ' ')
991 acc++;
993 if (strncmp (acc, "<Keys>", 6) == 0)
995 multi_key = 1;
996 acc ++;
998 else if (strncmp (acc, "<Key>", 5))
1000 fprintf (stderr, "accelerator \"%s\" not <Key> or <Keys>\n", orig_acc);
1001 return;
1004 /* We have a hard time specifying the Enter key the "usual" way. */
1005 if (strcmp (acc, "<Key>Enter") == 0)
1006 acc = "<Key>\r";
1008 acc += 5;
1009 if (acc[0] && acc[1] == 0)
1011 key_char = acc[0];
1012 a = find_or_create_acc (mods, key_char, 0, &acc_table, &acc_num);
1014 else if (multi_key)
1016 acc_table_t **ap = &acc_table;
1017 int *np = &acc_num;
1019 mods |= M_Multi;
1020 while (acc[0] && acc[1])
1022 a = find_or_create_acc (mods, acc[0], 0, ap, np);
1023 ap = & (a->u.c.chain);
1024 np = & (a->u.c.n_chain);
1025 acc ++;
1027 a = find_or_create_acc (mods & ~M_Multi, acc[0], 0, ap, np);
1029 else
1031 key = XStringToKeysym (acc);
1032 if (key == NoSymbol && !key_char)
1034 printf ("no symbol for %s\n", acc);
1035 return;
1037 a = find_or_create_acc (mods, 0, key, &acc_table, &acc_num);
1040 a->u.a.node = node;
1043 #if 0
1044 static void
1045 dump_multi (int ix, int ind, acc_table_t *a, int n)
1047 int i = ix;
1048 while (n--)
1050 if (a->mods & M_Multi)
1052 printf("%*cacc[%d] mods %x char %c multi %p/%d\n",
1053 ind, ' ',
1054 i, a->mods, a->key_char,
1055 a->u.c.chain, a->u.c.n_chain);
1056 dump_multi(0, ind+4, a->u.c.chain, a->u.c.n_chain);
1058 else
1060 printf("%*cacc[%d] mods %x char %c key %d node `%s'\n",
1061 ind, ' ',
1062 i, a->mods, a->key_char,
1063 a->u.a.key, a->u.a.node->v[0].value);
1065 a++;
1066 i++;
1069 #else
1070 #define dump_multi(x,a,b,c)
1071 #endif
1073 static acc_table_t *cur_table = 0;
1074 static int cur_ntable = 0;
1076 /* We sort these such that the ones with explicit modifiers come
1077 before the ones with implicit modifiers. That way, a
1078 Shift<Key>Code gets chosen before a <Key>Code. */
1079 static int
1080 acc_sort_rev (const void *va, const void *vb)
1082 acc_table_t *a = (acc_table_t *) va;
1083 acc_table_t *b = (acc_table_t *) vb;
1084 if (a->key_char != b->key_char)
1085 return a->key_char - b->key_char;
1086 if (!(a->mods & M_Multi))
1087 if (a->u.a.key != b->u.a.key)
1088 return a->u.a.key - b->u.a.key;
1089 return b->mods - a->mods;
1093 lesstif_key_event (XKeyEvent * e)
1095 char buf[10], buf2[10];
1096 KeySym sym, sym2;
1097 int slen, slen2;
1098 int mods = 0;
1099 int i, vi;
1100 static int sorted = 0;
1102 if (!sorted)
1104 sorted = 1;
1105 qsort (acc_table, acc_num, sizeof (acc_table_t), acc_sort_rev);
1108 if (e->state & ShiftMask)
1109 mods |= M_Shift;
1110 if (e->state & ControlMask)
1111 mods |= M_Ctrl;
1112 if (e->state & Mod1Mask)
1113 mods |= M_Alt;
1115 e->state &= ~(ControlMask | Mod1Mask);
1116 slen = XLookupString (e, buf, sizeof (buf), &sym, NULL);
1118 if (e->state & ShiftMask)
1120 e->state &= ~ShiftMask;
1121 slen2 = XLookupString (e, buf2, sizeof (buf2), &sym2, NULL);
1123 else
1124 slen2 = slen;
1126 /* Ignore these. */
1127 switch (sym)
1129 case XK_Shift_L:
1130 case XK_Shift_R:
1131 case XK_Control_L:
1132 case XK_Control_R:
1133 case XK_Caps_Lock:
1134 case XK_Shift_Lock:
1135 case XK_Meta_L:
1136 case XK_Meta_R:
1137 case XK_Alt_L:
1138 case XK_Alt_R:
1139 case XK_Super_L:
1140 case XK_Super_R:
1141 case XK_Hyper_L:
1142 case XK_Hyper_R:
1143 return 1;
1146 if (cur_table == 0)
1148 cur_table = acc_table;
1149 cur_ntable = acc_num;
1152 //printf("\nmods %x key %d str `%s' in %p/%d\n", mods, (int)sym, buf, cur_table, cur_ntable);
1154 #define KM(m) ((m) & ~M_Multi)
1155 for (i = 0; i < cur_ntable; i++)
1157 dump_multi (i, 0, cur_table+i, 1);
1158 if (KM(cur_table[i].mods) == mods)
1160 if (sym == acc_table[i].u.a.key)
1161 break;
1163 if (KM(cur_table[i].mods) == (mods & ~M_Shift))
1165 if (slen == 1 && buf[0] == cur_table[i].key_char)
1166 break;
1167 if (sym == cur_table[i].u.a.key)
1168 break;
1170 if (mods & M_Shift && KM(cur_table[i].mods) == mods)
1172 if (slen2 == 1 && buf2[0] == cur_table[i].key_char)
1173 break;
1174 if (sym2 == acc_table[i].u.a.key)
1175 break;
1179 if (i == cur_ntable)
1181 if (cur_table == acc_table)
1182 lesstif_log ("Key \"%s\" not tied to an action\n", buf);
1183 else
1184 lesstif_log ("Key \"%s\" not tied to a multi-key action\n", buf);
1185 cur_table = 0;
1186 return 0;
1188 if (cur_table[i].mods & M_Multi)
1190 cur_ntable = cur_table[i].u.c.n_chain;
1191 cur_table = cur_table[i].u.c.chain;
1192 dump_multi (0, 0, cur_table, cur_ntable);
1193 return 1;
1196 if (e->window == XtWindow (work_area))
1198 have_xy = 1;
1199 action_x = e->x;
1200 action_y = e->y;
1202 else
1203 have_xy = 0;
1205 for (vi = 1; vi < cur_table[i].u.a.node->c; vi++)
1206 if (resource_type (cur_table[i].u.a.node->v[vi]) == 10)
1207 if (hid_parse_actions
1208 (cur_table[i].u.a.node->v[vi].value))
1209 break;
1210 cur_table = 0;
1211 return 1;
1214 static void
1215 add_resource_to_menu (Widget menu, Resource * node, XtCallbackProc callback)
1217 int i, j;
1218 char *v;
1219 Widget sub, btn;
1220 Resource *r;
1222 for (i = 0; i < node->c; i++)
1223 switch (resource_type (node->v[i]))
1225 case 101: /* named subnode */
1226 n = 0;
1227 stdarg (XmNtearOffModel, XmTEAR_OFF_ENABLED);
1228 sub = XmCreatePulldownMenu (menu, node->v[i].name, args, n);
1229 XtSetValues (sub, args, n);
1230 n = 0;
1231 stdarg (XmNsubMenuId, sub);
1232 btn = XmCreateCascadeButton (menu, node->v[i].name, args, n);
1233 XtManageChild (btn);
1234 add_resource_to_menu (sub, node->v[i].subres, callback);
1235 break;
1237 case 1: /* unnamed subres */
1238 n = 0;
1239 #if 0
1240 if ((v = resource_value (node->v[i].subres, "fg")))
1242 do_color (v, XmNforeground);
1244 if ((v = resource_value (node->v[i].subres, "bg")))
1246 do_color (v, XmNbackground);
1248 if ((v = resource_value (node->v[i].subres, "font")))
1250 XFontStruct *fs = XLoadQueryFont (display, v);
1251 if (fs)
1253 XmFontList fl =
1254 XmFontListCreate (fs, XmSTRING_DEFAULT_CHARSET);
1255 stdarg (XmNfontList, fl);
1258 #endif
1259 if ((v = resource_value (node->v[i].subres, "m")))
1261 stdarg (XmNmnemonic, v);
1263 if ((r = resource_subres (node->v[i].subres, "a")))
1265 XmString as = XmStringCreateLocalized (r->v[0].value);
1266 stdarg (XmNacceleratorText, as);
1267 //stdarg(XmNaccelerator, r->v[1].value);
1268 note_accelerator (r->v[1].value, node->v[i].subres);
1270 v = "button";
1271 for (j = 0; j < node->v[i].subres->c; j++)
1272 if (resource_type (node->v[i].subres->v[j]) == 10)
1274 v = node->v[i].subres->v[j].value;
1275 break;
1277 stdarg (XmNlabelString, XmStringCreateLocalized (v));
1278 if (node->v[i].subres->flags & FLAG_S)
1280 int nn = n;
1281 stdarg (XmNtearOffModel, XmTEAR_OFF_ENABLED);
1282 sub = XmCreatePulldownMenu (menu, v, args + nn, n - nn);
1283 n = nn;
1284 stdarg (XmNsubMenuId, sub);
1285 btn = XmCreateCascadeButton (menu, "menubutton", args, n);
1286 XtManageChild (btn);
1287 add_resource_to_menu (sub, node->v[i].subres, callback);
1289 else
1291 Resource *radio = resource_subres (node->v[i].subres, "radio");
1292 char *checked = resource_value (node->v[i].subres, "checked");
1293 char *label = resource_value (node->v[i].subres, "sensitive");
1294 if (radio)
1296 ToggleItem *ti = (ToggleItem *) malloc (sizeof (ToggleItem));
1297 ti->next = toggle_items;
1298 ti->group = radio->v[0].value;
1299 ti->item = radio->v[1].value;
1300 ti->callback = callback;
1301 ti->node = node->v[i].subres;
1302 toggle_items = ti;
1304 if (resource_value (node->v[i].subres, "set"))
1306 stdarg (XmNset, True);
1308 stdarg (XmNindicatorType, XmONE_OF_MANY);
1309 btn = XmCreateToggleButton (menu, "menubutton", args, n);
1310 ti->w = btn;
1311 XtAddCallback (btn, XmNvalueChangedCallback,
1312 (XtCallbackProc) radio_callback,
1313 (XtPointer) ti);
1315 else if (checked)
1317 if (strchr (checked, ','))
1318 stdarg (XmNindicatorType, XmONE_OF_MANY);
1319 else
1320 stdarg (XmNindicatorType, XmN_OF_MANY);
1321 btn = XmCreateToggleButton (menu, "menubutton", args, n);
1322 XtAddCallback (btn, XmNvalueChangedCallback,
1323 callback, (XtPointer) node->v[i].subres);
1325 else if (label && strcmp (label, "false") == 0)
1327 stdarg (XmNalignment, XmALIGNMENT_BEGINNING);
1328 btn = XmCreateLabel (menu, "menulabel", args, n);
1330 else
1332 btn = XmCreatePushButton (menu, "menubutton", args, n);
1333 XtAddCallback (btn, XmNactivateCallback,
1334 callback, (XtPointer) node->v[i].subres);
1337 for (j = 0; j < node->v[i].subres->c; j++)
1338 switch (resource_type (node->v[i].subres->v[j]))
1340 case 110: /* named value = X resource */
1342 char *n = node->v[i].subres->v[j].name;
1343 if (strcmp (n, "fg") == 0)
1344 n = "foreground";
1345 if (strcmp (n, "bg") == 0)
1346 n = "background";
1347 if (strcmp (n, "m") == 0
1348 || strcmp (n, "a") == 0
1349 || strcmp (n, "sensitive") == 0)
1350 break;
1351 if (strcmp (n, "checked") == 0)
1353 note_widget_flag (btn, XmNset,
1354 node->v[i].subres->v[j].value);
1355 break;
1357 if (strcmp (n, "active") == 0)
1359 note_widget_flag (btn, XmNsensitive,
1360 node->v[i].subres->v[j].value);
1361 break;
1363 XtVaSetValues (btn, XtVaTypedArg,
1365 XtRString,
1366 node->v[i].subres->v[j].value,
1367 strlen (node->v[i].subres->v[j].value) + 1,
1368 NULL);
1370 break;
1373 XtManageChild (btn);
1375 break;
1377 case 10: /* unnamed value */
1378 n = 0;
1379 if (node->v[i].value[0] == '@')
1381 if (strcmp (node->v[i].value, "@layerview") == 0)
1382 insert_layerview_buttons (menu);
1383 if (strcmp (node->v[i].value, "@layerpick") == 0)
1384 insert_layerpick_buttons (menu);
1385 if (strcmp (node->v[i].value, "@routestyles") == 0)
1386 lesstif_insert_style_buttons (menu);
1388 else if (strcmp (node->v[i].value, "-") == 0)
1390 btn = XmCreateSeparator (menu, "sep", args, n);
1391 XtManageChild (btn);
1393 else if (i > 0)
1395 btn = XmCreatePushButton (menu, node->v[i].value, args, n);
1396 XtManageChild (btn);
1398 break;
1402 extern char *lesstif_pcbmenu_path;
1404 Widget
1405 lesstif_menu (Widget parent, char *name, Arg * margs, int mn)
1407 Widget mb = XmCreateMenuBar (parent, name, margs, mn);
1408 char *filename;
1409 Resource *r = 0, *bir;
1410 char *home_pcbmenu, *home;
1411 int screen;
1412 Resource *mr;
1414 display = XtDisplay (mb);
1415 screen = DefaultScreen (display);
1416 cmap = DefaultColormap (display, screen);
1418 /* homedir is set by the core */
1419 home = homedir;
1420 home_pcbmenu = NULL;
1421 if (home == NULL)
1423 Message ("Warning: could not determine home directory (from HOME)\n");
1425 else
1427 home_pcbmenu = Concat (home, PCB_DIR_SEPARATOR_S, ".pcb",
1428 PCB_DIR_SEPARATOR_S, "pcb-menu.res", NULL);
1431 if (access ("pcb-menu.res", R_OK) == 0)
1432 filename = "pcb-menu.res";
1433 else if (home_pcbmenu != NULL && (access (home_pcbmenu, R_OK) == 0))
1434 filename = home_pcbmenu;
1435 else if (access (lesstif_pcbmenu_path, R_OK) == 0)
1436 filename = lesstif_pcbmenu_path;
1437 else
1438 filename = 0;
1440 bir = resource_parse (0, pcb_menu_default);
1441 if (!bir)
1443 fprintf (stderr, "Error: internal menu resource didn't parse\n");
1444 exit(1);
1447 if (filename)
1448 r = resource_parse (filename, 0);
1450 if (!r)
1451 r = bir;
1453 if (home_pcbmenu != NULL)
1455 free (home_pcbmenu);
1458 mr = resource_subres (r, "MainMenu");
1459 if (!mr)
1460 mr = resource_subres (bir, "MainMenu");
1461 if (mr)
1462 add_resource_to_menu (mb, mr, (XtCallbackProc) callback);
1464 mr = resource_subres (r, "Mouse");
1465 if (!mr)
1466 mr = resource_subres (bir, "Mouse");
1467 if (mr)
1468 load_mouse_resource (mr);
1471 if (do_dump_keys)
1472 DumpKeys2 ();
1474 return mb;