Make SelectLayer() respond to layer name as well as index
[geda-pcb/whiteaudio.git] / src / hid / lesstif / menu.c
blobddaddcb224402cf5f0ec3df7976df950b3845e81
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <ctype.h>
9 #include <unistd.h>
11 #include "xincludes.h"
13 #include "global.h"
14 #include "data.h"
15 #include "error.h"
16 #include "misc.h"
17 #include "pcb-printf.h"
19 #include "hid.h"
20 #include "../hidint.h"
21 #include "hid/common/hid_resource.h"
22 #include "resource.h"
23 #include "lesstif.h"
24 #include "mymem.h"
26 #include "pcb-menu.h"
28 #ifdef HAVE_LIBDMALLOC
29 #include <dmalloc.h>
30 #endif
32 #ifndef R_OK
33 /* Common value for systems that don't define it. */
34 #define R_OK 4
35 #endif
37 static Colormap cmap;
39 static Arg args[30];
40 static int n;
41 #define stdarg(t,v) XtSetArg(args[n], t, v), n++
43 static void note_accelerator (char *acc, Resource * node);
44 static void note_widget_flag (Widget w, char *type, char *name);
46 static const char getxy_syntax[] =
47 "GetXY()";
49 static const char getxy_help[] =
50 "Get a coordinate.";
52 /* %start-doc actions GetXY
54 Prompts the user for a coordinate, if one is not already selected.
56 %end-doc */
58 static int
59 GetXY (int argc, char **argv, Coord x, Coord y)
61 return 0;
64 static const char debug_syntax[] =
65 "Debug(...)";
67 static const char debug_help[] =
68 "Debug action.";
70 /* %start-doc actions Debug
72 This action exists to help debug scripts; it simply prints all its
73 arguments to stdout.
75 %end-doc */
77 static const char debugxy_syntax[] =
78 "DebugXY(...)";
80 static const char debugxy_help[] =
81 "Debug action, with coordinates";
83 /* %start-doc actions DebugXY
85 Like @code{Debug}, but requires a coordinate. If the user hasn't yet
86 indicated a location on the board, the user will be prompted to click
87 on one.
89 %end-doc */
91 static int
92 Debug (int argc, char **argv, Coord x, Coord y)
94 int i;
95 printf ("Debug:");
96 for (i = 0; i < argc; i++)
97 printf (" [%d] `%s'", i, argv[i]);
98 pcb_printf (" x,y %$mD\n", x, y);
99 return 0;
102 static const char return_syntax[] =
103 "Return(0|1)";
105 static const char return_help[] =
106 "Simulate a passing or failing action.";
108 /* %start-doc actions Return
110 This is for testing. If passed a 0, does nothing and succeeds. If
111 passed a 1, does nothing but pretends to fail.
113 %end-doc */
115 static int
116 Return (int argc, char **argv, Coord x, Coord y)
118 return atoi (argv[0]);
121 static const char dumpkeys_syntax[] =
122 "DumpKeys()";
124 static const char dumpkeys_help[] =
125 "Dump Lesstif key bindings.";
127 /* %start-doc actions DumpKeys
129 Causes the list of key bindings (from @code{pcb-menu.res}) to be
130 dumped to stdout. This is most useful when invoked from the command
131 line like this:
133 @example
134 pcb --action-string DumpKeys
135 @end example
137 %end-doc */
139 static int do_dump_keys = 0;
140 static int
141 DumpKeys (int argc, char **argv, Coord x, Coord y)
143 do_dump_keys = 1;
144 return 0;
147 /*-----------------------------------------------------------------------------*/
149 #define LB_SILK (MAX_LAYER+0)
150 #define LB_RATS (MAX_LAYER+1)
151 #define LB_NUMPICK (LB_RATS+1)
152 /* more */
153 #define LB_PINS (MAX_LAYER+2)
154 #define LB_VIAS (MAX_LAYER+3)
155 #define LB_BACK (MAX_LAYER+4)
156 #define LB_MASK (MAX_LAYER+5)
157 #define LB_NUM (MAX_LAYER+6)
159 typedef struct
161 Widget w[LB_NUM];
162 int is_pick;
163 } LayerButtons;
165 static LayerButtons *layer_button_list = 0;
166 static int num_layer_buttons = 0;
167 static int fg_colors[LB_NUM];
168 static int bg_color;
170 extern Widget lesstif_m_layer;
172 static int
173 LayersChanged (int argc, char **argv, Coord x, Coord y)
175 int l, i, set;
176 char *name;
177 int current_layer;
179 if (!layer_button_list)
180 return 0;
181 if (PCB && PCB->Data)
183 DataType *d = PCB->Data;
184 for (i = 0; i < MAX_LAYER; i++)
185 fg_colors[i] = lesstif_parse_color (d->Layer[i].Color);
186 fg_colors[LB_SILK] = lesstif_parse_color (PCB->ElementColor);
187 fg_colors[LB_RATS] = lesstif_parse_color (PCB->RatColor);
188 fg_colors[LB_PINS] = lesstif_parse_color (PCB->PinColor);
189 fg_colors[LB_VIAS] = lesstif_parse_color (PCB->ViaColor);
190 fg_colors[LB_BACK] =
191 lesstif_parse_color (PCB->InvisibleObjectsColor);
192 fg_colors[LB_MASK] = lesstif_parse_color (PCB->MaskColor);
193 bg_color = lesstif_parse_color (Settings.BackgroundColor);
195 else
197 for (i = 0; i < MAX_LAYER; i++)
198 fg_colors[i] = lesstif_parse_color (Settings.LayerColor[i]);
199 fg_colors[LB_SILK] = lesstif_parse_color (Settings.ElementColor);
200 fg_colors[LB_RATS] = lesstif_parse_color (Settings.RatColor);
201 fg_colors[LB_PINS] = lesstif_parse_color (Settings.PinColor);
202 fg_colors[LB_VIAS] = lesstif_parse_color (Settings.ViaColor);
203 fg_colors[LB_BACK] =
204 lesstif_parse_color (Settings.InvisibleObjectsColor);
205 fg_colors[LB_MASK] = lesstif_parse_color (Settings.MaskColor);
206 bg_color = lesstif_parse_color (Settings.BackgroundColor);
209 if (PCB->RatDraw)
210 current_layer = LB_RATS;
211 else if (PCB->SilkActive)
212 current_layer = LB_SILK;
213 else
214 current_layer = LayerStack[0];
216 for (l = 0; l < num_layer_buttons; l++)
218 LayerButtons *lb = layer_button_list + l;
219 for (i = 0; i < (lb->is_pick ? LB_NUMPICK : LB_NUM); i++)
221 switch (i)
223 case LB_SILK:
224 set = PCB->ElementOn;
225 break;
226 case LB_RATS:
227 set = PCB->RatOn;
228 break;
229 case LB_PINS:
230 set = PCB->PinOn;
231 break;
232 case LB_VIAS:
233 set = PCB->ViaOn;
234 break;
235 case LB_BACK:
236 set = PCB->InvisibleObjectsOn;
237 break;
238 case LB_MASK:
239 set = TEST_FLAG (SHOWMASKFLAG, PCB);
240 break;
241 default: /* layers */
242 set = PCB->Data->Layer[i].On;
243 break;
246 n = 0;
247 if (i < MAX_LAYER && PCB->Data->Layer[i].Name)
249 XmString s = XmStringCreatePCB (PCB->Data->Layer[i].Name);
250 stdarg (XmNlabelString, s);
252 if (!lb->is_pick)
254 if (set)
256 stdarg (XmNforeground, bg_color);
257 stdarg (XmNbackground, fg_colors[i]);
259 else
261 stdarg (XmNforeground, fg_colors[i]);
262 stdarg (XmNbackground, bg_color);
264 stdarg (XmNset, set);
266 else
268 stdarg (XmNforeground, bg_color);
269 stdarg (XmNbackground, fg_colors[i]);
270 stdarg (XmNset, current_layer == i ? True : False);
272 XtSetValues (lb->w[i], args, n);
274 if (i >= max_copper_layer && i < MAX_LAYER)
275 XtUnmanageChild(lb->w[i]);
276 else
277 XtManageChild(lb->w[i]);
280 if (lesstif_m_layer)
282 switch (current_layer)
284 case LB_RATS:
285 name = "Rats";
286 break;
287 case LB_SILK:
288 name = "Silk";
289 break;
290 default:
291 name = PCB->Data->Layer[current_layer].Name;
292 break;
294 n = 0;
295 stdarg (XmNbackground, fg_colors[current_layer]);
296 stdarg (XmNforeground, bg_color);
297 stdarg (XmNlabelString, XmStringCreatePCB (name));
298 XtSetValues (lesstif_m_layer, args, n);
301 lesstif_update_layer_groups ();
303 return 0;
306 static void
307 show_one_layer_button (int layer, int set)
309 int l;
310 n = 0;
311 if (set)
313 stdarg (XmNforeground, bg_color);
314 stdarg (XmNbackground, fg_colors[layer]);
316 else
318 stdarg (XmNforeground, fg_colors[layer]);
319 stdarg (XmNbackground, bg_color);
321 stdarg (XmNset, set);
323 for (l = 0; l < num_layer_buttons; l++)
325 LayerButtons *lb = layer_button_list + l;
326 if (!lb->is_pick)
327 XtSetValues (lb->w[layer], args, n);
331 static void
332 layer_button_callback (Widget w, int layer, XmPushButtonCallbackStruct * pbcs)
334 int l, set;
335 switch (layer)
337 case LB_SILK:
338 set = PCB->ElementOn = !PCB->ElementOn;
339 PCB->Data->SILKLAYER.On = set;
340 PCB->Data->BACKSILKLAYER.On = set;
341 break;
342 case LB_RATS:
343 set = PCB->RatOn = !PCB->RatOn;
344 break;
345 case LB_PINS:
346 set = PCB->PinOn = !PCB->PinOn;
347 break;
348 case LB_VIAS:
349 set = PCB->ViaOn = !PCB->ViaOn;
350 break;
351 case LB_BACK:
352 set = PCB->InvisibleObjectsOn = !PCB->InvisibleObjectsOn;
353 break;
354 case LB_MASK:
355 TOGGLE_FLAG (SHOWMASKFLAG, PCB);
356 set = TEST_FLAG (SHOWMASKFLAG, PCB);
357 break;
358 default: /* layers */
359 set = PCB->Data->Layer[layer].On = !PCB->Data->Layer[layer].On;
360 break;
363 show_one_layer_button (layer, set);
364 if (layer < max_copper_layer)
366 int i;
367 int group = GetLayerGroupNumberByNumber (layer);
368 for (i = 0; i < PCB->LayerGroups.Number[group]; i++)
370 l = PCB->LayerGroups.Entries[group][i];
371 if (l != layer && l < max_copper_layer)
373 show_one_layer_button (l, set);
374 PCB->Data->Layer[l].On = set;
378 lesstif_invalidate_all ();
381 static void
382 layerpick_button_callback (Widget w, int layer,
383 XmPushButtonCallbackStruct * pbcs)
385 int l, i;
386 char *name;
387 PCB->RatDraw = (layer == LB_RATS);
388 PCB->SilkActive = (layer == LB_SILK);
389 if (layer < max_copper_layer)
390 ChangeGroupVisibility (layer, 1, 1);
391 for (l = 0; l < num_layer_buttons; l++)
393 LayerButtons *lb = layer_button_list + l;
394 if (!lb->is_pick)
395 continue;
396 for (i = 0; i < LB_NUMPICK; i++)
397 XmToggleButtonSetState (lb->w[i], layer == i, False);
399 switch (layer)
401 case LB_RATS:
402 name = "Rats";
403 break;
404 case LB_SILK:
405 name = "Silk";
406 break;
407 default:
408 name = PCB->Data->Layer[layer].Name;
409 break;
411 n = 0;
412 stdarg (XmNbackground, fg_colors[layer]);
413 stdarg (XmNforeground, bg_color);
414 stdarg (XmNlabelString, XmStringCreatePCB (name));
415 XtSetValues (lesstif_m_layer, args, n);
416 lesstif_invalidate_all ();
419 static const char selectlayer_syntax[] =
420 "SelectLayer(1..MAXLAYER|Silk|Rats)";
422 static const char selectlayer_help[] =
423 "Select which layer is the current layer.";
425 /* %start-doc actions SelectLayer
427 The specified layer becomes the currently active layer. It is made
428 visible if it is not already visible
430 %end-doc */
432 static int
433 SelectLayer (int argc, char **argv, Coord x, Coord y)
435 int i;
436 int newl = -1;
437 if (argc == 0)
438 return 1;
440 for (i = 0; i < max_copper_layer; ++i)
441 if (strcasecmp (argv[0], PCB->Data->Layer[i].Name) == 0)
442 newl = i;
444 if (strcasecmp (argv[0], "silk") == 0)
445 newl = LB_SILK;
446 else if (strcasecmp (argv[0], "rats") == 0)
447 newl = LB_RATS;
448 else if (newl == -1)
449 newl = atoi (argv[0]) - 1;
450 layerpick_button_callback (0, newl, 0);
451 return 0;
454 static const char toggleview_syntax[] =
455 "ToggleView(1..MAXLAYER)\n"
456 "ToggleView(layername)\n"
457 "ToggleView(Silk|Rats|Pins|Vias|Mask|BackSide)";
459 static const char toggleview_help[] =
460 "Toggle the visibility of the specified layer or layer group.";
462 /* %start-doc actions ToggleView
464 If you pass an integer, that layer is specified by index (the first
465 layer is @code{1}, etc). If you pass a layer name, that layer is
466 specified by name. When a layer is specified, the visibility of the
467 layer group containing that layer is toggled.
469 If you pass a special layer name, the visibility of those components
470 (silk, rats, etc) is toggled. Note that if you have a layer named
471 the same as a special layer, the layer is chosen over the special layer.
473 %end-doc */
475 static int
476 ToggleView (int argc, char **argv, Coord x, Coord y)
478 int i, l;
480 if (argc == 0)
481 return 1;
482 if (isdigit ((int) argv[0][0]))
484 l = atoi (argv[0]) - 1;
485 layer_button_callback (0, l, 0);
487 else if (strcmp (argv[0], "Silk") == 0)
488 layer_button_callback (0, LB_SILK, 0);
489 else if (strcmp (argv[0], "Rats") == 0)
490 layer_button_callback (0, LB_RATS, 0);
491 else if (strcmp (argv[0], "Pins") == 0)
492 layer_button_callback (0, LB_PINS, 0);
493 else if (strcmp (argv[0], "Vias") == 0)
494 layer_button_callback (0, LB_VIAS, 0);
495 else if (strcmp (argv[0], "Mask") == 0)
496 layer_button_callback (0, LB_MASK, 0);
497 else if (strcmp (argv[0], "BackSide") == 0)
498 layer_button_callback (0, LB_BACK, 0);
499 else
501 l = -1;
502 for (i = 0; i < max_copper_layer + 2; i++)
503 if (strcmp (argv[0], PCB->Data->Layer[i].Name) == 0)
505 l = i;
506 break;
508 if (l == -1)
509 return 1;
510 layer_button_callback (0, l, 0);
512 return 0;
515 static void
516 insert_layerview_buttons (Widget menu)
518 int i, s;
519 LayerButtons *lb;
521 num_layer_buttons++;
522 s = num_layer_buttons * sizeof (LayerButtons);
523 if (layer_button_list)
524 layer_button_list = (LayerButtons *) realloc (layer_button_list, s);
525 else
526 layer_button_list = (LayerButtons *) malloc (s);
527 lb = layer_button_list + num_layer_buttons - 1;
529 for (i = 0; i < LB_NUM; i++)
531 static char namestr[] = "Label ";
532 char *name = namestr;
533 int accel_idx = i;
534 Widget btn;
535 name[5] = 'A' + i;
536 switch (i)
538 case LB_SILK:
539 name = "Silk";
540 accel_idx = max_copper_layer;
541 break;
542 case LB_RATS:
543 name = "Rat Lines";
544 accel_idx = max_copper_layer + 1;
545 break;
546 case LB_PINS:
547 name = "Pins/Pads";
548 break;
549 case LB_VIAS:
550 name = "Vias";
551 break;
552 case LB_BACK:
553 name = "Far Side";
554 break;
555 case LB_MASK:
556 name = "Solder Mask";
557 break;
559 n = 0;
560 if (accel_idx < 9)
562 char buf[20], av[30];
563 Resource *ar;
564 XmString as;
565 sprintf (buf, "Ctrl-%d", accel_idx + 1);
566 as = XmStringCreatePCB (buf);
567 stdarg (XmNacceleratorText, as);
568 ar = resource_create (0);
569 sprintf (av, "ToggleView(%d)", i + 1);
570 resource_add_val (ar, 0, strdup (av), 0);
571 resource_add_val (ar, 0, strdup (av), 0);
572 ar->flags |= FLAG_V;
573 sprintf (av, "Ctrl<Key>%d", accel_idx + 1);
574 note_accelerator (av, ar);
575 stdarg (XmNmnemonic, accel_idx + '1');
577 btn = XmCreateToggleButton (menu, name, args, n);
578 XtManageChild (btn);
579 XtAddCallback (btn, XmNvalueChangedCallback,
580 (XtCallbackProc) layer_button_callback, (XtPointer) (size_t) i);
581 lb->w[i] = btn;
583 if (i == LB_MASK)
584 note_widget_flag (btn, XmNset, "showmask");
586 lb->is_pick = 0;
587 LayersChanged (0, 0, 0, 0);
590 static void
591 insert_layerpick_buttons (Widget menu)
593 int i, s;
594 LayerButtons *lb;
596 num_layer_buttons++;
597 s = num_layer_buttons * sizeof (LayerButtons);
598 if (layer_button_list)
599 layer_button_list = (LayerButtons *) realloc (layer_button_list, s);
600 else
601 layer_button_list = (LayerButtons *) malloc (s);
602 lb = layer_button_list + num_layer_buttons - 1;
604 for (i = 0; i < LB_NUMPICK; i++)
606 static char namestr[] = "Label ";
607 char *name = namestr;
608 int accel_idx = i;
609 char buf[20], av[30];
610 Widget btn;
611 name[5] = 'A' + i;
612 switch (i)
614 case LB_SILK:
615 name = "Silk";
616 accel_idx = max_copper_layer;
617 strcpy (av, "SelectLayer(Silk)");
618 break;
619 case LB_RATS:
620 name = "Rat Lines";
621 accel_idx = max_copper_layer + 1;
622 strcpy (av, "SelectLayer(Rats)");
623 break;
624 default:
625 sprintf (av, "SelectLayer(%d)", i + 1);
626 break;
628 n = 0;
629 if (accel_idx < 9)
631 Resource *ar;
632 XmString as;
633 ar = resource_create (0);
634 resource_add_val (ar, 0, strdup (av), 0);
635 resource_add_val (ar, 0, strdup (av), 0);
636 ar->flags |= FLAG_V;
637 sprintf (buf, "%d", i + 1);
638 as = XmStringCreatePCB (buf);
639 stdarg (XmNacceleratorText, as);
640 sprintf (av, "<Key>%d", accel_idx + 1);
641 note_accelerator (av, ar);
642 stdarg (XmNmnemonic, accel_idx + '1');
644 stdarg (XmNindicatorType, XmONE_OF_MANY);
645 btn = XmCreateToggleButton (menu, name, args, n);
646 XtManageChild (btn);
647 XtAddCallback (btn, XmNvalueChangedCallback,
648 (XtCallbackProc) layerpick_button_callback,
649 (XtPointer) (size_t) i);
650 lb->w[i] = btn;
652 lb->is_pick = 1;
653 LayersChanged (0, 0, 0, 0);
656 /*-----------------------------------------------------------------------------*/
658 typedef struct
660 Widget w;
661 const char *flagname;
662 int oldval;
663 char *xres;
664 } WidgetFlagType;
666 static WidgetFlagType *wflags = 0;
667 static int n_wflags = 0;
668 static int max_wflags = 0;
670 static void
671 note_widget_flag (Widget w, char *type, char *name)
673 if (n_wflags >= max_wflags)
675 max_wflags += 20;
676 wflags = (WidgetFlagType *) realloc (wflags, max_wflags * sizeof (WidgetFlagType));
678 wflags[n_wflags].w = w;
679 wflags[n_wflags].flagname = name;
680 wflags[n_wflags].oldval = -1;
681 wflags[n_wflags].xres = type;
682 n_wflags++;
685 void
686 lesstif_update_widget_flags ()
688 int i;
690 for (i = 0; i < n_wflags; i++)
692 int v = hid_get_flag (wflags[i].flagname);
693 Arg args[1];
694 XtSetArg (args[0], wflags[i].xres, v ? 1 : 0);
695 XtSetValues (wflags[i].w, args, 1);
696 wflags[i].oldval = v;
700 /*-----------------------------------------------------------------------------*/
702 HID_Action lesstif_menu_action_list[] = {
703 {"DumpKeys", 0, DumpKeys,
704 dumpkeys_help, dumpkeys_syntax},
705 {"Debug", 0, Debug,
706 debug_help, debug_syntax},
707 {"DebugXY", "Click X,Y for Debug", Debug,
708 debugxy_help, debugxy_syntax},
709 {"GetXY", "", GetXY,
710 getxy_help, getxy_syntax},
711 {"Return", 0, Return,
712 return_help, return_syntax},
713 {"LayersChanged", 0, LayersChanged,
714 layerschanged_help, layerschanged_syntax},
715 {"ToggleView", 0, ToggleView,
716 toggleview_help, toggleview_syntax},
717 {"SelectLayer", 0, SelectLayer,
718 selectlayer_help, selectlayer_syntax}
721 REGISTER_ACTIONS (lesstif_menu_action_list)
723 #if 0
724 static void
725 do_color (char *value, char *which)
727 XColor color;
728 if (XParseColor (display, cmap, value, &color))
729 if (XAllocColor (display, cmap, &color))
731 stdarg (which, color.pixel);
734 #endif
736 typedef struct ToggleItem
738 struct ToggleItem *next;
739 Widget w;
740 char *group, *item;
741 XtCallbackProc callback;
742 Resource *node;
743 } ToggleItem;
744 static ToggleItem *toggle_items = 0;
746 static int need_xy = 0, have_xy = 0, action_x, action_y;
748 static void
749 radio_callback (Widget toggle, ToggleItem * me,
750 XmToggleButtonCallbackStruct * cbs)
752 if (!cbs->set) /* uh uh, can't turn it off */
753 XmToggleButtonSetState (toggle, 1, 0);
754 else
756 ToggleItem *ti;
757 for (ti = toggle_items; ti; ti = ti->next)
758 if (strcmp (me->group, ti->group) == 0)
760 if (me->item == ti->item || strcmp (me->item, ti->item) == 0)
761 XmToggleButtonSetState (ti->w, 1, 0);
762 else
763 XmToggleButtonSetState (ti->w, 0, 0);
765 me->callback (toggle, me->node, cbs);
770 lesstif_button_event (Widget w, XEvent * e)
772 have_xy = 1;
773 action_x = e->xbutton.x;
774 action_y = e->xbutton.y;
775 if (!need_xy)
776 return 0;
777 if (w != work_area)
778 return 1;
779 return 0;
782 void
783 lesstif_get_xy (const char *message)
785 XmString ls = XmStringCreatePCB ((char *)message);
787 XtManageChild (m_click);
788 n = 0;
789 stdarg (XmNlabelString, ls);
790 XtSetValues (m_click, args, n);
791 //printf("need xy: msg `%s'\n", msg);
792 need_xy = 1;
793 XBell (display, 100);
794 while (!have_xy)
796 XEvent e;
797 XtAppNextEvent (app_context, &e);
798 XtDispatchEvent (&e);
800 need_xy = 0;
801 have_xy = 1;
802 XtUnmanageChild (m_click);
805 void
806 lesstif_get_coords (const char *msg, Coord *px, Coord *py)
808 if (!have_xy && msg)
809 lesstif_get_xy (msg);
810 if (have_xy)
811 lesstif_coords_to_pcb (action_x, action_y, px, py);
814 static void
815 callback (Widget w, Resource * node, XmPushButtonCallbackStruct * pbcs)
817 int vi;
818 have_xy = 0;
819 lesstif_show_crosshair (0);
820 if (pbcs->event && pbcs->event->type == KeyPress)
822 Dimension wx, wy;
823 Widget aw = XtWindowToWidget (display, pbcs->event->xkey.window);
824 action_x = pbcs->event->xkey.x;
825 action_y = pbcs->event->xkey.y;
826 if (aw)
828 Widget p = work_area;
829 while (p && p != aw)
831 n = 0;
832 stdarg (XmNx, &wx);
833 stdarg (XmNy, &wy);
834 XtGetValues (p, args, n);
835 action_x -= wx;
836 action_y -= wy;
837 p = XtParent (p);
839 if (p == aw)
840 have_xy = 1;
842 //pcb_printf("have xy from %s: %$mD\n", XtName(aw), action_x, action_y);
845 lesstif_need_idle_proc ();
846 for (vi = 1; vi < node->c; vi++)
847 if (resource_type (node->v[vi]) == 10)
848 if (hid_parse_actions (node->v[vi].value))
849 return;
852 typedef struct acc_table_t
854 char mods;
855 char key_char;
856 union {
857 /* If M_Multi is set in mods, these are used to chain to the next
858 attribute table for multi-key accelerators. */
859 struct {
860 int n_chain;
861 struct acc_table_t *chain;
862 } c;
863 /* If M_Multi isn't set, these are used to map a single key to an
864 event. */
865 struct {
866 KeySym key;
867 Resource *node;
868 } a;
869 } u;
870 } acc_table_t;
872 static acc_table_t *acc_table;
873 static int acc_num = 0;
875 static int
876 acc_sort (const void *va, const void *vb)
878 acc_table_t *a = (acc_table_t *) va;
879 acc_table_t *b = (acc_table_t *) vb;
880 if (a->key_char != b->key_char)
881 return a->key_char - b->key_char;
882 if (!(a->mods & M_Multi))
883 if (a->u.a.key != b->u.a.key)
884 return a->u.a.key - b->u.a.key;
885 return a->mods - b->mods;
888 static int
889 DumpKeys2 ()
891 int i;
892 char ch[2];
893 printf ("in dumpkeys! %d\n", acc_num);
894 qsort (acc_table, acc_num, sizeof (acc_table_t), acc_sort);
895 ch[1] = 0;
896 for (i = 0; i < acc_num; i++)
898 char mod[16];
899 int vi;
900 char *tabs = "";
902 sprintf (mod, "%s%s%s",
903 acc_table[i].mods & M_Alt ? "Alt-" : "",
904 acc_table[i].mods & M_Ctrl ? "Ctrl-" : "",
905 acc_table[i].mods & M_Shift ? "Shift-" : "");
906 ch[0] = toupper ((int) acc_table[i].key_char);
907 printf ("%16s%s\t", mod,
908 acc_table[i].key_char ? ch : XKeysymToString (acc_table[i].
909 u.a.key));
911 for (vi = 1; vi < acc_table[i].u.a.node->c; vi++)
912 if (resource_type (acc_table[i].u.a.node->v[vi]) == 10)
914 printf ("%s%s", tabs, acc_table[i].u.a.node->v[vi].value);
915 tabs = "\n\t\t\t ";
918 printf ("\n");
920 exit (0);
923 static acc_table_t *
924 find_or_create_acc (char mods, char key, KeySym sym,
925 acc_table_t **table, int *n_ents)
927 int i, max;
928 acc_table_t *a;
930 if (*table)
931 for (i=(*n_ents)-1; i>=0; i--)
933 a = & (*table)[i];
934 if (a->mods == mods
935 && a->key_char == key
936 && (mods & M_Multi || a->u.a.key == sym))
937 return a;
940 (*n_ents) ++;
941 max = (*n_ents + 16) & ~15;
943 if (*table)
944 *table = (acc_table_t *) realloc (*table, max * sizeof (acc_table_t));
945 else
946 *table = (acc_table_t *) malloc (max * sizeof (acc_table_t));
948 a = & ((*table)[(*n_ents)-1]);
949 memset (a, 0, sizeof(acc_table_t));
951 a->mods = mods;
952 a->key_char = key;
953 if (!(mods & M_Multi))
954 a->u.a.key = sym;
956 return a;
959 static void
960 note_accelerator (char *acc, Resource * node)
962 char *orig_acc = acc;
963 int mods = 0;
964 acc_table_t *a;
965 char key_char = 0;
966 KeySym key = 0;
967 int multi_key = 0;
969 while (isalpha ((int) acc[0]))
971 if (strncmp (acc, "Shift", 5) == 0)
973 mods |= M_Shift;
974 acc += 5;
976 else if (strncmp (acc, "Ctrl", 4) == 0)
978 mods |= M_Ctrl;
979 acc += 4;
981 else if (strncmp (acc, "Alt", 3) == 0)
983 mods |= M_Alt;
984 acc += 3;
986 else
988 printf ("Must be Shift/Ctrl/Alt: %s\n", acc);
989 return;
991 while (*acc == ' ')
992 acc++;
994 if (strncmp (acc, "<Keys>", 6) == 0)
996 multi_key = 1;
997 acc ++;
999 else if (strncmp (acc, "<Key>", 5))
1001 fprintf (stderr, "accelerator \"%s\" not <Key> or <Keys>\n", orig_acc);
1002 return;
1005 /* We have a hard time specifying the Enter key the "usual" way. */
1006 if (strcmp (acc, "<Key>Enter") == 0)
1007 acc = "<Key>\r";
1009 acc += 5;
1010 if (acc[0] && acc[1] == 0)
1012 key_char = acc[0];
1013 a = find_or_create_acc (mods, key_char, 0, &acc_table, &acc_num);
1015 else if (multi_key)
1017 acc_table_t **ap = &acc_table;
1018 int *np = &acc_num;
1020 mods |= M_Multi;
1021 while (acc[0] && acc[1])
1023 a = find_or_create_acc (mods, acc[0], 0, ap, np);
1024 ap = & (a->u.c.chain);
1025 np = & (a->u.c.n_chain);
1026 acc ++;
1028 a = find_or_create_acc (mods & ~M_Multi, acc[0], 0, ap, np);
1030 else
1032 key = XStringToKeysym (acc);
1033 if (key == NoSymbol && !key_char)
1035 printf ("no symbol for %s\n", acc);
1036 return;
1038 a = find_or_create_acc (mods, 0, key, &acc_table, &acc_num);
1041 a->u.a.node = node;
1044 #if 0
1045 static void
1046 dump_multi (int ix, int ind, acc_table_t *a, int n)
1048 int i = ix;
1049 while (n--)
1051 if (a->mods & M_Multi)
1053 printf("%*cacc[%d] mods %x char %c multi %p/%d\n",
1054 ind, ' ',
1055 i, a->mods, a->key_char,
1056 a->u.c.chain, a->u.c.n_chain);
1057 dump_multi(0, ind+4, a->u.c.chain, a->u.c.n_chain);
1059 else
1061 printf("%*cacc[%d] mods %x char %c key %d node `%s'\n",
1062 ind, ' ',
1063 i, a->mods, a->key_char,
1064 a->u.a.key, a->u.a.node->v[0].value);
1066 a++;
1067 i++;
1070 #else
1071 #define dump_multi(x,a,b,c)
1072 #endif
1074 static acc_table_t *cur_table = 0;
1075 static int cur_ntable = 0;
1077 /* We sort these such that the ones with explicit modifiers come
1078 before the ones with implicit modifiers. That way, a
1079 Shift<Key>Code gets chosen before a <Key>Code. */
1080 static int
1081 acc_sort_rev (const void *va, const void *vb)
1083 acc_table_t *a = (acc_table_t *) va;
1084 acc_table_t *b = (acc_table_t *) vb;
1085 if (a->key_char != b->key_char)
1086 return a->key_char - b->key_char;
1087 if (!(a->mods & M_Multi))
1088 if (a->u.a.key != b->u.a.key)
1089 return a->u.a.key - b->u.a.key;
1090 return b->mods - a->mods;
1094 lesstif_key_event (XKeyEvent * e)
1096 char buf[10], buf2[10];
1097 KeySym sym, sym2;
1098 int slen, slen2;
1099 int mods = 0;
1100 int i, vi;
1101 static int sorted = 0;
1102 acc_table_t *my_table = 0;
1104 if (!sorted)
1106 sorted = 1;
1107 qsort (acc_table, acc_num, sizeof (acc_table_t), acc_sort_rev);
1110 if (e->state & ShiftMask)
1111 mods |= M_Shift;
1112 if (e->state & ControlMask)
1113 mods |= M_Ctrl;
1114 if (e->state & Mod1Mask)
1115 mods |= M_Alt;
1117 e->state &= ~(ControlMask | Mod1Mask);
1118 slen = XLookupString (e, buf, sizeof (buf), &sym, NULL);
1120 if (e->state & ShiftMask)
1122 e->state &= ~ShiftMask;
1123 slen2 = XLookupString (e, buf2, sizeof (buf2), &sym2, NULL);
1125 else
1126 slen2 = slen;
1128 /* Ignore these. */
1129 switch (sym)
1131 case XK_Shift_L:
1132 case XK_Shift_R:
1133 case XK_Control_L:
1134 case XK_Control_R:
1135 case XK_Caps_Lock:
1136 case XK_Shift_Lock:
1137 case XK_Meta_L:
1138 case XK_Meta_R:
1139 case XK_Alt_L:
1140 case XK_Alt_R:
1141 case XK_Super_L:
1142 case XK_Super_R:
1143 case XK_Hyper_L:
1144 case XK_Hyper_R:
1145 case XK_ISO_Level3_Shift:
1146 return 1;
1149 if (cur_table == 0)
1151 cur_table = acc_table;
1152 cur_ntable = acc_num;
1155 //printf("\nmods %x key %d str `%s' in %p/%d\n", mods, (int)sym, buf, cur_table, cur_ntable);
1157 #define KM(m) ((m) & ~M_Multi)
1158 for (i = 0; i < cur_ntable; i++)
1160 dump_multi (i, 0, cur_table+i, 1);
1161 if (KM(cur_table[i].mods) == mods)
1163 if (sym == acc_table[i].u.a.key)
1164 break;
1166 if (KM(cur_table[i].mods) == (mods & ~M_Shift))
1168 if (slen == 1 && buf[0] == cur_table[i].key_char)
1169 break;
1170 if (sym == cur_table[i].u.a.key)
1171 break;
1173 if (mods & M_Shift && KM(cur_table[i].mods) == mods)
1175 if (slen2 == 1 && buf2[0] == cur_table[i].key_char)
1176 break;
1177 if (sym2 == acc_table[i].u.a.key)
1178 break;
1182 if (i == cur_ntable)
1184 if (cur_table == acc_table)
1185 lesstif_log ("Key \"%s\" not tied to an action\n", buf);
1186 else
1187 lesstif_log ("Key \"%s\" not tied to a multi-key action\n", buf);
1188 cur_table = 0;
1189 return 0;
1191 if (cur_table[i].mods & M_Multi)
1193 cur_ntable = cur_table[i].u.c.n_chain;
1194 cur_table = cur_table[i].u.c.chain;
1195 dump_multi (0, 0, cur_table, cur_ntable);
1196 return 1;
1199 if (e->window == XtWindow (work_area))
1201 have_xy = 1;
1202 action_x = e->x;
1203 action_y = e->y;
1205 else
1206 have_xy = 0;
1208 /* Parsing actions may not return until more user interaction
1209 happens, so remember which table we're scanning. */
1210 my_table = cur_table;
1211 for (vi = 1; vi < my_table[i].u.a.node->c; vi++)
1212 if (resource_type (my_table[i].u.a.node->v[vi]) == 10)
1213 if (hid_parse_actions
1214 (my_table[i].u.a.node->v[vi].value))
1215 break;
1216 cur_table = 0;
1217 return 1;
1220 static void
1221 add_resource_to_menu (Widget menu, Resource * node, XtCallbackProc callback)
1223 int i, j;
1224 char *v;
1225 Widget sub, btn;
1226 Resource *r;
1228 for (i = 0; i < node->c; i++)
1229 switch (resource_type (node->v[i]))
1231 case 101: /* named subnode */
1232 n = 0;
1233 stdarg (XmNtearOffModel, XmTEAR_OFF_ENABLED);
1234 sub = XmCreatePulldownMenu (menu, node->v[i].name, args, n);
1235 XtSetValues (sub, args, n);
1236 n = 0;
1237 stdarg (XmNsubMenuId, sub);
1238 btn = XmCreateCascadeButton (menu, node->v[i].name, args, n);
1239 XtManageChild (btn);
1240 add_resource_to_menu (sub, node->v[i].subres, callback);
1241 break;
1243 case 1: /* unnamed subres */
1244 n = 0;
1245 #if 0
1246 if ((v = resource_value (node->v[i].subres, "fg")))
1248 do_color (v, XmNforeground);
1250 if ((v = resource_value (node->v[i].subres, "bg")))
1252 do_color (v, XmNbackground);
1254 if ((v = resource_value (node->v[i].subres, "font")))
1256 XFontStruct *fs = XLoadQueryFont (display, v);
1257 if (fs)
1259 XmFontList fl =
1260 XmFontListCreate (fs, XmSTRING_DEFAULT_CHARSET);
1261 stdarg (XmNfontList, fl);
1264 #endif
1265 if ((v = resource_value (node->v[i].subres, "m")))
1267 stdarg (XmNmnemonic, v);
1269 if ((r = resource_subres (node->v[i].subres, "a")))
1271 XmString as = XmStringCreatePCB (r->v[0].value);
1272 stdarg (XmNacceleratorText, as);
1273 //stdarg(XmNaccelerator, r->v[1].value);
1274 note_accelerator (r->v[1].value, node->v[i].subres);
1276 v = "button";
1277 for (j = 0; j < node->v[i].subres->c; j++)
1278 if (resource_type (node->v[i].subres->v[j]) == 10)
1280 v = node->v[i].subres->v[j].value;
1281 break;
1283 stdarg (XmNlabelString, XmStringCreatePCB (v));
1284 if (node->v[i].subres->flags & FLAG_S)
1286 int nn = n;
1287 stdarg (XmNtearOffModel, XmTEAR_OFF_ENABLED);
1288 sub = XmCreatePulldownMenu (menu, v, args + nn, n - nn);
1289 n = nn;
1290 stdarg (XmNsubMenuId, sub);
1291 btn = XmCreateCascadeButton (menu, "menubutton", args, n);
1292 XtManageChild (btn);
1293 add_resource_to_menu (sub, node->v[i].subres, callback);
1295 else
1297 Resource *radio = resource_subres (node->v[i].subres, "radio");
1298 char *checked = resource_value (node->v[i].subres, "checked");
1299 char *label = resource_value (node->v[i].subres, "sensitive");
1300 if (radio)
1302 ToggleItem *ti = (ToggleItem *) malloc (sizeof (ToggleItem));
1303 ti->next = toggle_items;
1304 ti->group = radio->v[0].value;
1305 ti->item = radio->v[1].value;
1306 ti->callback = callback;
1307 ti->node = node->v[i].subres;
1308 toggle_items = ti;
1310 if (resource_value (node->v[i].subres, "set"))
1312 stdarg (XmNset, True);
1314 stdarg (XmNindicatorType, XmONE_OF_MANY);
1315 btn = XmCreateToggleButton (menu, "menubutton", args, n);
1316 ti->w = btn;
1317 XtAddCallback (btn, XmNvalueChangedCallback,
1318 (XtCallbackProc) radio_callback,
1319 (XtPointer) ti);
1321 else if (checked)
1323 if (strchr (checked, ','))
1324 stdarg (XmNindicatorType, XmONE_OF_MANY);
1325 else
1326 stdarg (XmNindicatorType, XmN_OF_MANY);
1327 btn = XmCreateToggleButton (menu, "menubutton", args, n);
1328 XtAddCallback (btn, XmNvalueChangedCallback,
1329 callback, (XtPointer) node->v[i].subres);
1331 else if (label && strcmp (label, "false") == 0)
1333 stdarg (XmNalignment, XmALIGNMENT_BEGINNING);
1334 btn = XmCreateLabel (menu, "menulabel", args, n);
1336 else
1338 btn = XmCreatePushButton (menu, "menubutton", args, n);
1339 XtAddCallback (btn, XmNactivateCallback,
1340 callback, (XtPointer) node->v[i].subres);
1343 for (j = 0; j < node->v[i].subres->c; j++)
1344 switch (resource_type (node->v[i].subres->v[j]))
1346 case 110: /* named value = X resource */
1348 char *n = node->v[i].subres->v[j].name;
1349 if (strcmp (n, "fg") == 0)
1350 n = "foreground";
1351 if (strcmp (n, "bg") == 0)
1352 n = "background";
1353 if (strcmp (n, "m") == 0
1354 || strcmp (n, "a") == 0
1355 || strcmp (n, "sensitive") == 0)
1356 break;
1357 if (strcmp (n, "checked") == 0)
1359 note_widget_flag (btn, XmNset,
1360 node->v[i].subres->v[j].value);
1361 break;
1363 if (strcmp (n, "active") == 0)
1365 note_widget_flag (btn, XmNsensitive,
1366 node->v[i].subres->v[j].value);
1367 break;
1369 XtVaSetValues (btn, XtVaTypedArg,
1371 XtRString,
1372 node->v[i].subres->v[j].value,
1373 strlen (node->v[i].subres->v[j].value) + 1,
1374 NULL);
1376 break;
1379 XtManageChild (btn);
1381 break;
1383 case 10: /* unnamed value */
1384 n = 0;
1385 if (node->v[i].value[0] == '@')
1387 if (strcmp (node->v[i].value, "@layerview") == 0)
1388 insert_layerview_buttons (menu);
1389 if (strcmp (node->v[i].value, "@layerpick") == 0)
1390 insert_layerpick_buttons (menu);
1391 if (strcmp (node->v[i].value, "@routestyles") == 0)
1392 lesstif_insert_style_buttons (menu);
1394 else if (strcmp (node->v[i].value, "-") == 0)
1396 btn = XmCreateSeparator (menu, "sep", args, n);
1397 XtManageChild (btn);
1399 else if (i > 0)
1401 btn = XmCreatePushButton (menu, node->v[i].value, args, n);
1402 XtManageChild (btn);
1404 break;
1408 extern char *lesstif_pcbmenu_path;
1410 Widget
1411 lesstif_menu (Widget parent, char *name, Arg * margs, int mn)
1413 Widget mb = XmCreateMenuBar (parent, name, margs, mn);
1414 char *filename;
1415 Resource *r = 0, *bir;
1416 char *home_pcbmenu, *home;
1417 int screen;
1418 Resource *mr;
1420 display = XtDisplay (mb);
1421 screen = DefaultScreen (display);
1422 cmap = DefaultColormap (display, screen);
1424 /* homedir is set by the core */
1425 home = homedir;
1426 home_pcbmenu = NULL;
1427 if (home == NULL)
1429 Message ("Warning: could not determine home directory (from HOME)\n");
1431 else
1433 home_pcbmenu = Concat (home, PCB_DIR_SEPARATOR_S, ".pcb",
1434 PCB_DIR_SEPARATOR_S, "pcb-menu.res", NULL);
1437 if (access ("pcb-menu.res", R_OK) == 0)
1438 filename = "pcb-menu.res";
1439 else if (home_pcbmenu != NULL && (access (home_pcbmenu, R_OK) == 0))
1440 filename = home_pcbmenu;
1441 else if (access (lesstif_pcbmenu_path, R_OK) == 0)
1442 filename = lesstif_pcbmenu_path;
1443 else
1444 filename = 0;
1446 bir = resource_parse (0, pcb_menu_default);
1447 if (!bir)
1449 fprintf (stderr, "Error: internal menu resource didn't parse\n");
1450 exit(1);
1453 if (filename)
1454 r = resource_parse (filename, 0);
1456 if (!r)
1457 r = bir;
1459 if (home_pcbmenu != NULL)
1461 free (home_pcbmenu);
1464 mr = resource_subres (r, "MainMenu");
1465 if (!mr)
1466 mr = resource_subres (bir, "MainMenu");
1467 if (mr)
1468 add_resource_to_menu (mb, mr, (XtCallbackProc) callback);
1470 mr = resource_subres (r, "Mouse");
1471 if (!mr)
1472 mr = resource_subres (bir, "Mouse");
1473 if (mr)
1474 load_mouse_resource (mr);
1477 if (do_dump_keys)
1478 DumpKeys2 ();
1480 return mb;