1 /*******************************************************************
2 FILE: Control.c
3 CONTENTS: Definitions for structures, methods, and actions of the
4 Control widget.
5 AUTHOR: Paul D. Johnston
6 HISTORY:
7 Date Action
8 --------- ------------------------------------
9 5/23/92 Changed the widget class name so that it is preceded
10 by 'xc' with the first major word capitalized.
11 5/18/92 Changed Label resource processing so that it copies a " "
12 to the label pointer instead of "NO LABEL".
13 10/22/91 Created.
14
15 ********************************************************************/
16
17 #include <stdio.h>
18
19 /* Xlib includes */
20 #include <X11/Xlib.h>
21
22 /* Xt includes */
23 #include <X11/StringDefs.h>
24 #include <X11/IntrinsicP.h>
25 #ifdef X11R3
26 #include <X11/Xmu.h>
27 #else
28 #include <X11/Xmu/Xmu.h>
29 #endif
30
31 /* Widget includes */
32 #include <X11/Xc/ControlP.h> /* (includes Control.h also) */
33
34
35 /* Macro redefinition for offset. */
36 #define offset(field) XtOffset(ControlWidget, field)
37
38 /* Constants used in 3D rectangle color generation. */
39 #define MAX_RGB 65280
40 #define SHADE_INTENSITY ((unsigned short)(MAX_RGB / 4))
41
42 /* Data for the bitmap used for the 3D shading effect. */
43 #define shade_width 2
44 #define shade_height 2
45 static char shade_bits[] = { 0x02, 0x01};
46
47 /* Declare widget methods */
48 static void Initialize();
49 static void Destroy();
50 static Boolean SetValues();
51
52
53
54 /* Define the widget's resource list */
55 static XtResource resources[] =
56 {
57 {
58 XcNbackground,
59 XtCColor,
60 XtRPixel,
61 sizeof(Pixel),
62 offset(control.background_pixel),
63 XtRString,
64 "gray"
65 },
66 {
67 XcNlabelColor,
68 XtCColor,
69 XtRPixel,
70 sizeof(Pixel),
71 offset(control.label_pixel),
72 XtRString,
73 XtDefaultForeground
74 },
75 {
76 XcNlabel,
77 XcCLabel,
78 XtRString,
79 sizeof(String),
80 offset(control.label),
81 XtRString,
82 " "
83 },
84 {
85 XtNfont,
86 XtCFont,
87 XtRFontStruct,
88 sizeof(XFontStruct *),
89 offset(control.font),
90 XtRString,
91 XtDefaultFont
92 },
93 {
94 XcNshadeDepth,
95 XcCShadeDepth,
96 XtRInt,
97 sizeof(int),
98 offset(control.shade_depth),
99 XtRString,
100 "3"
101 },
102
103 };
104
105
106
107 /* Widget Class Record initialization */
108 ControlClassRec controlClassRec =
109 {
110 {
111 /* core_class part */
112 (WidgetClass) &widgetClassRec, /* superclass */
113 "Control", /* class_name */
114 sizeof(ControlRec), /* widget_size */
115 NULL, /* class_initialize */
116 NULL, /* class_part_initialize */
117 FALSE, /* class_inited */
118 Initialize, /* initialize */
119 NULL, /* initialize_hook */
120 XtInheritRealize, /* realize */
121 NULL, /* actions */
122 0, /* num_actions */
123 resources, /* resources */
124 XtNumber(resources), /* num_resources */
125 NULLQUARK, /* xrm_class */
126 TRUE, /* compress_motion */
127 TRUE, /* compress_exposure */
128 TRUE, /* compress_enterleave */
129 TRUE, /* visible_interest */
130 Destroy, /* destroy */
131 NULL, /* resize */
132 NULL, /* expose */
133 SetValues, /* set_values */
134 NULL, /* set_values_hook */
135 XtInheritSetValuesAlmost, /* set_values_almost */
136 NULL, /* get_values_hook */
137 NULL, /* accept_focus */
138 XtVersion, /* version */
139 NULL, /* callback_private */
140 NULL, /* tm_table */
141 NULL, /* query_geometry */
142 NULL, /* display_accelerator */
143 NULL, /* extension */
144 },
145 {
146 /* Control class part */
147 0, /* dummy_field */
148 },
149 };
150
151 WidgetClass xcControlWidgetClass = (WidgetClass)&controlClassRec;
152
153
154 /* Widget method function definitions */
155
156 /*******************************************************************
157 NAME: Initialize.
158 DESCRIPTION:
159 This is the initialize method for the Control widget. It
160 validates user-modifiable instance resources and initializes private
161 widget variables and structures. This function also creates any server
162 resources (i.e., GCs, fonts, Pixmaps, etc.) used by this widget. This
163 method is called by Xt when the application calls XtCreateWidget().
164
165 *******************************************************************/
166
Initialize(request,new)167 static void Initialize(request, new)
168 ControlWidget request, new;
169 {
170 /* Local variables */
171 XColor bg, exact;
172 Display *display = XtDisplay(new);
173 int scr = DefaultScreen(XtDisplay(new));
174 XGCValues values;
175 XtGCMask mask;
176 static char dash_list[2] = { 1, 1 };
177
178 #ifdef NICE_SHADES
179 /* These macros are used for calculating the 3D shade colors. */
180 #define COLOR_ADD(member) \
181 if (((int)bg.member + (int)SHADE_INTENSITY) <= MAX_RGB) \
182 new->control.shade1.member = bg.member + SHADE_INTENSITY; \
183 else new->control.shade1.member = MAX_RGB; \
184
185 #define COLOR_SUBTRACT(member) \
186 if (((int)bg.member - (int)SHADE_INTENSITY) >= 0) \
187 new->control.shade2.member = bg.member - SHADE_INTENSITY; \
188 else new->control.shade2.member = 0; \
189
190
191 /*
192 * Determine whether or not a backgroud color resource has been set for
193 * this widget, and if so, what its RGB values are. If no color has been
194 * established, set gray as its background by default.
195 */
196 if (new->control.background_pixel)
197 {
198 bg.pixel = new->control.background_pixel;
199 XQueryColor(display, DefaultColormap(display, scr), &bg);
200 }
201 else
202 {
203 if (XAllocNamedColor(display, DefaultColormap(display, scr),
204 "gray", &bg, &exact))
205 new->control.background_pixel = bg.pixel;
206 else
207 XtWarning("Control: unable to alloc default bg\n");
208 }
209
210 /*
211 * Calculate the 3D rectangle shades based on the background color RGB
212 * values, and allocate the corresponding colors.
213 */
214 COLOR_ADD(red);
215 COLOR_ADD(green);
216 COLOR_ADD(blue);
217 COLOR_SUBTRACT(red);
218 COLOR_SUBTRACT(green);
219 COLOR_SUBTRACT(blue);
220 if (XAllocColor(display, DefaultColormap(display, scr),
221 &(new->control.shade1)) == 0)
222 {
223 XtWarning("Control: unable to alloc shade 1 color\n");
224 new->control.shade1.pixel = WhitePixel(display, DefaultScreen(display));
225 }
226 if (XAllocColor(display, DefaultColormap(display, scr),
227 &(new->control.shade2)) == 0)
228 {
229 XtWarning("Control: unable to alloc shade 2 color\n");
230 new->control.shade2.pixel = BlackPixel(display, DefaultScreen(display));
231 }
232 #endif /* NICE_SHADES */
233
234
235 /*
236 * Validate public instance variable settings.
237 */
238 if (strlen(new->control.label) == 0)
239 {
240 XtWarning("Control: invalid or missing label string.");
241 strcpy(new->control.label, " ");
242 }
243
244 if ((new->control.shade_depth < MIN_SHADE_DEPTH) ||
245 (new->control.shade_depth > MAX_SHADE_DEPTH))
246 {
247 XtWarning("Control: invalid shadeDepth specification.");
248 new->control.shade_depth = 3;
249 }
250
251
252 /* Create the GC used by all subclasses for drawing in this widget. */
253 values.graphics_exposures = False;
254 values.foreground = new->control.label_pixel;
255 values.background = new->control.background_pixel;
256 values.font = new->control.font->fid;
257 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
258 if ((new->control.gc = XCreateGC(display,
259 RootWindowOfScreen(XtScreen(new)),
260 mask, &values)) == NULL)
261 XtWarning("Control: couldn't create GC");
262
263 /* Set basic line attributes used in drawing this widget. */
264 XSetLineAttributes(display, new->control.gc, 0, LineSolid,
265 CapButt, JoinRound);
266 XSetDashes(display, new->control.gc, 0, dash_list, 2);
267
268
269 } /* end of Initialize */
270
271
272
273
274 /*******************************************************************
275 NAME: SetValues.
276 DESCRIPTION:
277 This is the set_values method for this widget. It validates resource
278 settings set with XtSetValues. If a resource is changed that would
279 require re-drawing the widget, return True.
280
281 *******************************************************************/
282
SetValues(cur,req,new)283 static Boolean SetValues(cur, req, new)
284 ControlWidget cur, req, new;
285 {
286 /* Local variables */
287 Boolean do_redisplay = False;
288
289
290 /* Validate new resource settings. */
291 /* Check to see if the labelColor has changed. */
292 if (new->control.label_pixel != cur->control.label_pixel)
293 do_redisplay = True;
294
295 /* Check for valid shadeDepth setting. */
296 if (new->control.shade_depth != cur->control.shade_depth)
297 {
298 do_redisplay = True;
299 if ((new->control.shade_depth < MIN_SHADE_DEPTH) ||
300 (new->control.shade_depth > MAX_SHADE_DEPTH))
301 {
302 XtWarning("Control: invalid shadeDepth setting.");
303 new->control.shade_depth = 3;
304 }
305 }
306
307 /* Check for a valid label */
308 if (strcmp(new->control.label, cur->control.label) != 0)
309 {
310 if (strlen(new->control.label) == 0)
311 {
312 XtWarning("Control: invalid Label setting.");
313 if (new->control.label != NULL)
314 strcpy(new->control.label, " ");
315 }
316 do_redisplay = True;
317 }
318
319 return do_redisplay;
320
321
322 } /* end of SetValues */
323
324
325
326 /*******************************************************************
327 NAME: Destroy.
328 DESCRIPTION:
329 This function is the widget's destroy method. It simply releases
330 any server resources acquired during the life of the widget.
331
332 *******************************************************************/
333
Destroy(w)334 static void Destroy(w)
335 ControlWidget w;
336 {
337
338 if (w->control.gc)
339 XFreeGC(XtDisplay(w), w->control.gc);
340
341 } /* end of Destroy */
342
343
344
345
346
347 /* Functions shared by widget subclasses. */
348
349 /***************************************************************************
350 FUNCTION: Point_In_Rect.
351 DESCRIPTION:
352 This function simply checks to see if the given point is within the
353 given rectangle and returns TRUE if it is, or FALSE if it isn't within
354 the rectangle.
355
356 ***************************************************************************/
357
Point_In_Rect(x,y,rect_x,rect_y,width,height)358 Boolean Point_In_Rect( /* RETURN: True or False; identifies whether
359 * or not the point is in the
360 * rectangle.
361 */
362
363 x, /* INPUT: The x coordinate of the point */
364
365 y, /* INPUT: The y coordinate of the point */
366
367 rect_x, /* INPUT: The x coordinate of the rectangle */
368
369 rect_y, /* INPUT: The y coordinate of the rectangle */
370
371 width, /* INPUT: The rectangle's width */
372
373 height) /* INPUT: The rectangle's height */
374
375 int x,
376 y,
377 rect_x,
378 rect_y,
379 width,
380 height;
381 {
382 /* Check x coordinate first */
383 if ((x < rect_x) || (x > (rect_x + width)))
384 return False;
385
386 /* Check y coordinate next. If its within the rectangle, return True. */
387 if ((y < rect_y) || (y > (rect_y + height)))
388 return False;
389
390 return True;
391
392 } /* end of Point_In_Rect */
393
394
395
396
397
398
399 /*******************************************************************
400 NAME: Rect3d.
401 DESCRIPTION:
402 This function generates a filled rectangle with a 3D effect in
403 the given drawable. It uses the widget's background color and the
404 derived shades (calculated in the Initialize method) to produce the
405 3D rectangle.
406
407 *******************************************************************/
408
Rect3d(w,display,drawable,gc,x,y,width,height,type)409 void Rect3d(w, display, drawable, gc, x, y, width, height, type)
410 ControlWidget w;
411 Display *display;
412 Drawable drawable;
413 GC gc;
414 int x, y;
415 unsigned int width, height;
416 Type3d type;
417 {
418 int j;
419 unsigned long shade1, shade2;
420
421 /* Set basic GC attributes used in drawing the 3D rectangle. */
422 #ifdef NICE_SHADES
423 shade1 = w->control.shade1.pixel;
424 shade2 = w->control.shade2.pixel;
425 #else
426 shade1 = WhitePixel(display, DefaultScreen(display));
427 shade2 = BlackPixel(display, DefaultScreen(display));
428 XSetLineAttributes(display, gc, 0, LineOnOffDash, CapButt, JoinRound);
429 #endif
430
431 /* Draw the shadow lines */
432 for (j = 0; j < w->control.shade_depth; j++)
433 {
434 if (type == RAISED)
435 XSetForeground(display, gc, shade1);
436 else
437 XSetForeground(display, gc, shade2);
438 XDrawLine(display, drawable, gc, x+j, y+j, x+j, y+height-j);
439 XDrawLine(display, drawable, gc, x+j, y+j, x+width-j, y+j);
440
441 if (type == RAISED)
442 XSetForeground(display, gc, shade2);
443 else
444 XSetForeground(display, gc, shade1);
445 XDrawLine(display, drawable, gc, x+j, y+height-j, x+width-j, y+height-j);
446 XDrawLine(display, drawable, gc, x+width-j, y+j, x+width-j, y+height-j);
447 }
448
449 /* Fill in the background. */
450 XSetFillStyle(display, gc, FillSolid);
451 XSetLineAttributes(display, gc, 0, LineSolid, CapButt, JoinRound);
452 XSetForeground(display, gc, w->control.background_pixel);
453 if ((width > (2 * w->control.shade_depth)) &&
454 (height > (2 * w->control.shade_depth)))
455 XFillRectangle(display, drawable, gc, x+w->control.shade_depth,
456 y+w->control.shade_depth, width-(2 * w->control.shade_depth),
457 height-(2 * w->control.shade_depth));
458
459
460 } /* end of Rect3d */
461
462
463
464 /*******************************************************************
465 NAME: VarRect3d.
466 DESCRIPTION:
467 This function generates a filled rectangle with a 3D effect in
468 the given drawable. It uses the widget's background color and the
469 derived shades (calculated in the Initialize method) to produce the
470 3D rectangle.
471
472 *******************************************************************/
473
VarRect3d(w,display,drawable,gc,x,y,width,height,type,depth)474 void VarRect3d(w, display, drawable, gc, x, y, width, height, type, depth)
475 ControlWidget w;
476 Display *display;
477 Drawable drawable;
478 GC gc;
479 int x, y;
480 unsigned int width, height;
481 Type3d type;
482 int depth;
483 {
484 int j = ((depth < 1) ? 1 : depth);
485 unsigned long shade1, shade2;
486
487 /* Set basic line attributes used in drawing the 3D rectangle. */
488 #ifdef NICE_SHADES
489 shade1 = w->control.shade1.pixel;
490 shade2 = w->control.shade2.pixel;
491 #else
492 shade1 = WhitePixel(display, DefaultScreen(display));
493 shade2 = BlackPixel(display, DefaultScreen(display));
494 XSetLineAttributes(display, gc, 0, LineOnOffDash, CapButt, JoinRound);
495 #endif
496
497 /* Draw the shadow lines */
498 for (j = 0; j < w->control.shade_depth; j++)
499 {
500 if (type == RAISED)
501 XSetForeground(display, gc, shade1);
502 else
503 XSetForeground(display, gc, shade2);
504 XDrawLine(display, drawable, gc, x+j, y+j, x+j, y+height-j);
505 XDrawLine(display, drawable, gc, x+j, y+j, x+width-j, y+j);
506
507 if (type == RAISED)
508 XSetForeground(display, gc, shade2);
509 else
510 XSetForeground(display, gc, shade1);
511 XDrawLine(display, drawable, gc, x+j, y+height-j, x+width-j, y+height-j);
512 XDrawLine(display, drawable, gc, x+width-j, y+j, x+width-j, y+height-j);
513 }
514
515 /* Fill in the background. */
516 XSetLineAttributes(display, gc, 0, LineSolid, CapButt, JoinRound);
517 XSetFillStyle(display, gc, FillSolid);
518 XSetForeground(display, gc, w->control.background_pixel);
519 if ((width > (2 * depth)) && (height > (2 * depth)))
520 XFillRectangle(display, drawable, gc, x + depth,
521 y + depth, width-(2 * depth), height-(2 * depth));
522
523
524 } /* end of VarRect3d */
525
526
527
528 /*******************************************************************
529 NAME: ToLower.
530 DESCRIPTION:
531 Converts a character string to all lowercase for use in the
532 resource string conversion routines.
533
534 *******************************************************************/
535
ToLower(source,dest)536 void ToLower(source, dest)
537 char *source, *dest;
538 {
539 /* Local variables */
540 char ch;
541
542 for (; (ch = *source) != 0; source++, dest++)
543 {
544 if ('A' <= ch && ch <= 'Z')
545 *dest = ch - 'A' + 'a';
546 else
547 *dest = ch;
548 }
549
550 *dest = 0;
551
552 } /* end of ToLower */
553
554
555
556
557 /*******************************************************************
558 NAME: CvtStringToOrient.
559 DESCRIPTION:
560 This function converts resource settings in string form to the
561 XcROrient representation type.
562
563 *******************************************************************/
564
CvtStringToOrient(args,num_args,fromVal,toVal)565 void CvtStringToOrient(args, num_args, fromVal, toVal)
566 XrmValuePtr args; /* unused */
567 Cardinal *num_args; /* unused */
568 XrmValuePtr fromVal;
569 XrmValuePtr toVal;
570 {
571 /* Local variables */
572 static XcOrient orient;
573 char lowerstring[100];
574
575
576 /* Convert the resource string to lower case for quick comparison */
577 ToLower((char *)fromVal->addr, lowerstring);
578
579
580 /*
581 * Compare resource string with valid XcOrient strings and assign to
582 * datatype.
583 */
584 if (strcmp(lowerstring, XcEvert) == 0)
585 {
586 orient = XcVert;
587 CvtDone(XcOrient, &orient);
588 }
589 else if (strcmp(lowerstring, XcEhoriz) == 0)
590 {
591 orient = XcHoriz;
592 CvtDone(XcOrient, &orient);
593 }
594
595 /*
596 * If the string is not valid for this resource type, print a warning
597 * and do not make the conversion.
598 */
599 XtStringConversionWarning(fromVal->addr, "XcOrient");
600 toVal->addr = NULL;
601 toVal->size = 0;
602
603 } /* end of CvtStringToOrient */
604
605
606
607 /*******************************************************************
608 NAME: Arrow3d.
609 DESCRIPTION:
610 This function generates a filled arrow polygon with a 3D effect in
611 the given drawable. It uses the widget's background color and the
612 derived shades (calculated in Control's Initialize method) to produce the
613 3D effect.
614
615 *******************************************************************/
616
Arrow3d(w,display,drawable,gc,bounds,orientation,type)617 void Arrow3d(w, display, drawable, gc, bounds, orientation, type)
618 ControlWidget w;
619 Display *display;
620 Drawable drawable;
621 GC gc;
622 XRectangle *bounds;
623 ArrowType orientation;
624 Type3d type;
625 {
626 /* Local variables */
627 int i, j, adjustment = w->control.shade_depth+1;
628 XPoint points[4];
629 unsigned long shade1, shade2;
630
631 /* Set basic line attributes used in drawing the 3D arrow. */
632 #ifdef NICE_SHADES
633 shade1 = w->control.shade1.pixel;
634 shade2 = w->control.shade2.pixel;
635 #else
636 shade1 = WhitePixel(display, DefaultScreen(display));
637 shade2 = BlackPixel(display, DefaultScreen(display));
638 XSetLineAttributes(display, gc, 0, LineOnOffDash, CapButt, JoinRound);
639 #endif
640
641 /* This macro is used to determine the shading color to use. */
642 #define SET_SHADE( sh1, sh2 ) \
643 if (type == RAISED) XSetForeground(display, gc, sh1); \
644 else XSetForeground(display, gc, sh2); \
645
646
647 /*
648 * Calculate the arrow vertices based on the bounding rectangle and
649 * orientation.
650 */
651 if (orientation == UP)
652 {
653 /* left corner */
654 points[0].x = bounds->x;
655 points[0].y = bounds->y + bounds->height;
656 /* arrow tip */
657 points[1].x = points[0].x + (bounds->width / 2 + 0.5);
658 points[1].y = bounds->y;
659 /* right corner */
660 points[2].x = points[0].x + bounds->width;
661 points[2].y = points[0].y;
662 }
663 else if (orientation == DOWN)
664 {
665 /* left corner */
666 points[0].x = bounds->x;
667 points[0].y = bounds->y;
668 /* arrow tip */
669 points[1].x = points[0].x + (bounds->width / 2 + 0.5);
670 points[1].y = bounds->y + bounds->height;
671 /* right corner */
672 points[2].x = points[0].x + bounds->width;
673 points[2].y = points[0].y;
674 }
675 else if (orientation == LEFT)
676 {
677 /* left corner */
678 points[0].x = bounds->x + bounds->width;
679 points[0].y = bounds->y + bounds->height;
680 /* arrow tip */
681 points[1].x = bounds->x;
682 points[1].y = bounds->y + (bounds->height / 2 + 0.5);
683 /* right corner */
684 points[2].x = points[0].x;
685 points[2].y = bounds->y;
686 }
687 else if (orientation == RIGHT)
688 {
689 /* left corner */
690 points[0].x = bounds->x;
691 points[0].y = bounds->y;
692 /* arrow tip */
693 points[1].x = bounds->x + bounds->width;
694 points[1].y = bounds->y + (bounds->height / 2 + 0.5);
695 /* right corner */
696 points[2].x = points[0].x;
697 points[2].y = bounds->y + bounds->height;
698 }
699
700 /* left corner */
701 points[3].x = points[0].x;
702 points[3].y = points[0].y;
703
704
705 /* Draw the shadow lines */
706 for (j = 0; j < w->control.shade_depth; j++)
707 {
708 if (orientation == UP)
709 {
710 SET_SHADE(shade1, shade2);
711 XDrawLine(display, drawable, gc, points[0].x+j, points[0].y-j,
712 points[1].x, points[1].y+j);
713 XDrawLine(display, drawable, gc, points[1].x, points[1].y+j,
714 points[2].x-j, points[2].y-j);
715 SET_SHADE(shade2, shade1);
716 XDrawLine(display, drawable, gc, points[2].x-j, points[2].y-j,
717 points[3].x+j, points[3].y-j);
718 }
719 else if (orientation == DOWN)
720 {
721 SET_SHADE(shade2, shade1);
722 XDrawLine(display, drawable, gc, points[0].x+j, points[0].y+j,
723 points[1].x, points[1].y-j);
724 XDrawLine(display, drawable, gc, points[1].x, points[1].y-j,
725 points[2].x-j, points[2].y+j);
726 SET_SHADE(shade1, shade2);
727 XDrawLine(display, drawable, gc, points[2].x-j, points[3].y+j,
728 points[3].x+j, points[3].y+j);
729 }
730 else if (orientation == LEFT)
731 {
732 SET_SHADE(shade2, shade1);
733 XDrawLine(display, drawable, gc, points[0].x-j, points[0].y-j,
734 points[1].x+j, points[1].y);
735 SET_SHADE(shade1, shade2);
736 XDrawLine(display, drawable, gc, points[1].x+j, points[1].y,
737 points[2].x-j, points[2].y+j);
738 SET_SHADE(shade2, shade1);
739 XDrawLine(display, drawable, gc, points[2].x-j, points[2].y+j,
740 points[3].x-j, points[3].y-j);
741 }
742 else if (orientation == RIGHT)
743 {
744 SET_SHADE(shade1, shade2);
745 XDrawLine(display, drawable, gc, points[0].x+j, points[0].y+j,
746 points[1].x-j, points[1].y);
747 SET_SHADE(shade2, shade1);
748 XDrawLine(display, drawable, gc, points[1].x-j, points[1].y,
749 points[2].x+j, points[2].y-j);
750 SET_SHADE(shade1, shade2);
751 XDrawLine(display, drawable, gc, points[2].x+j, points[2].y-j,
752 points[3].x+j, points[3].y+j);
753 }
754 }
755
756 XSetLineAttributes(display, gc, 0, LineSolid, CapButt, JoinRound);
757 XSetFillStyle(display, gc, FillSolid);
758
759 } /* end of Arrow3d */
760
761
762 /* end of Control.c */
763
764