1 #ifndef lint
2 static char *rcsid = "$Id: AuxPanel.c,v 1.23 1994/09/01 06:33:41 ishisone Exp $";
3 #endif
4 /*
5  * Copyright (c) 1990  Software Research Associates, Inc.
6  *
7  * Permission to use, copy, modify, and distribute this software and its
8  * documentation for any purpose and without fee is hereby granted, provided
9  * that the above copyright notice appear in all copies and that both that
10  * copyright notice and this permission notice appear in supporting
11  * documentation, and that the name of Software Research Associates not be
12  * used in advertising or publicity pertaining to distribution of the
13  * software without specific, written prior permission.  Software Research
14  * Associates makes no representations about the suitability of this software
15  * for any purpose.  It is provided "as is" without express or implied
16  * warranty.
17  *
18  * Author:  Makoto Ishisone, Software Research Associates, Inc., Japan
19  */
20 
21 /* Copyright 1991 NEC Corporation, Tokyo, Japan.
22  *
23  * Permission to use, copy, modify, and distribute this software and its
24  * documentation for any purpose and without fee is hereby granted,
25  * provided that the above copyright notice appear in all copies and that
26  * both that copyright notice and this permission notice appear in
27  * supporting documentation, and that the name of NEC Corporation
28  * not be used in advertising or publicity pertaining to distribution
29  * of the software without specific, written prior permission.  NEC
30  * Corporation makes no representations about the suitability of this
31  * software for any purpose.  It is provided "as is" without express
32  * or implied warranty.
33  *
34  * NEC CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
35  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
36  * NO EVENT SHALL NEC CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
37  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
38  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
39  * OTHER TORTUOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
40  * PERFORMANCE OF THIS SOFTWARE.
41  *
42  * Author: Akira Kon, NEC Corporation.  (kon@d1.bs2.mt.nec.co.jp)
43  */
44 
45 /*
46   $BLdBjE@(B
47   $B!&J8;zIA2h$,A4It=q$-D>$7=hM}$K$J$C$F$$$k!#(B
48   $B!&$@$l$b(B Destroy $B$r8F$s$G$/$l$J$$$N$G$A$g$C$H$4$_$,;D$k!#(B
49  */
50 
51 #include <X11/IntrinsicP.h>
52 #include <X11/StringDefs.h>
53 #if XtSpecificationRelease > 4
54 #include <X11/Xfuncs.h>
55 #endif
56 #include "AuxPanelP.h"
57 #include "ConvDisp.h"
58 #include "WStr.h"
59 
60 #define DEBUG_VAR debug_AuxPanel
61 #include "DebugPrint.h"
62 
63 static XtResource resources[] = {
64 #define offset(field) XtOffset(AuxPanelWidget, cpanel.field)
65     { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
66 	offset(foreground), XtRString, XtDefaultForeground },
67     { XtNhorizontalSpacing, XtCSpacing, XtRDimension, sizeof(Dimension),
68 	offset(hspace), XtRString, "6" },
69     { XtNverticalSpacing, XtCSpacing, XtRDimension, sizeof(Dimension),
70 	offset(vspace), XtRString, "4" },
71     { XtNdefaultWidth, XtCDefaultWidth, XtRDimension, sizeof(Dimension),
72 	offset(defaultwidth), XtRString, "400" },
73     { XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
74 	offset(cursor), XtRImmediate, (XtPointer)None },
75     { XtNcallback, XtCCallback, XtRCallback, sizeof(XtPointer),
76 	offset(callback), XtRCallback, NULL },
77 #undef offset
78 };
79 
80 static void Initialize(), Destroy();
81 static void Realize();
82 static void Redisplay();
83 static void Resize();
84 static Boolean SetValues();
85 static XtGeometryResult QueryGeometry();
86 static void InsertChild();
87 
88 static void GetInvGC();
89 static void ComputeSize();
90 static void Layout();
91 
92 static void freeDisplaySegments();
93 static void UpdateAuxDisplay();
94 
95 static CompositeClassExtensionRec CompositeExtension = {
96     /* next_extension		*/	NULL,
97     /* record_type		*/	NULLQUARK,
98     /* version			*/	XtCompositeExtensionVersion,
99     /* record_size		*/	sizeof(CompositeClassExtensionRec),
100     /* accept_objects		*/	True,
101 };
102 
103 AuxPanelClassRec auxPanelClassRec = {
104   { /* core fields */
105     /* superclass		*/	(WidgetClass) &compositeClassRec,
106     /* class_name		*/	"AuxPanel",
107     /* widget_size		*/	sizeof(AuxPanelRec),
108     /* class_initialize		*/	NULL,
109     /* class_part_initialize	*/	NULL,
110     /* class_inited		*/	FALSE,
111     /* initialize		*/	Initialize,
112     /* initialize_hook		*/	NULL,
113     /* realize			*/	Realize,
114     /* actions			*/	NULL,
115     /* num_actions		*/	0,
116     /* resources		*/	resources,
117     /* num_resources		*/	XtNumber(resources),
118     /* xrm_class		*/	NULLQUARK,
119     /* compress_motion		*/	TRUE,
120     /* compress_exposure	*/	TRUE,
121     /* compress_enterleave	*/	TRUE,
122     /* visible_interest		*/	FALSE,
123     /* destroy			*/	Destroy,
124     /* resize			*/	Resize,
125     /* expose			*/	Redisplay,
126     /* set_values		*/	SetValues,
127     /* set_values_hook		*/	NULL,
128     /* set_values_almost	*/	XtInheritSetValuesAlmost,
129     /* get_values_hook		*/	NULL,
130     /* accept_focus		*/	NULL,
131     /* version			*/	XtVersion,
132     /* callback_private		*/	NULL,
133     /* tm_table			*/	NULL,
134     /* query_geometry		*/	QueryGeometry,
135     /* display_accelerator	*/	XtInheritDisplayAccelerator,
136     /* extension		*/	NULL
137   },
138   { /* composite fields */
139     /* geometry_manager		*/	NULL,
140     /* change_managed		*/	NULL,
141     /* insert_child		*/	InsertChild,
142     /* delete_child		*/	XtInheritDeleteChild,
143     /* extension		*/	(XtPointer)&CompositeExtension,
144   },
145   { /* auxpanel fields */
146     /* empty			*/	0
147   }
148 };
149 
150 WidgetClass auxPanelWidgetClass = (WidgetClass)&auxPanelClassRec;
151 
152 /* ARGSUSED */
153 static void
Initialize(req,new,args,num_args)154 Initialize(req, new, args, num_args)
155 Widget req;
156 Widget new;
157 ArgList args;
158 Cardinal *num_args;
159 {
160     AuxPanelWidget cpw = (AuxPanelWidget)new;
161 
162     TRACE(("AuxPanel:Initialize()\n"));
163 
164     cpw->cpanel.displayobj = NULL;
165     cpw->cpanel.dispauxsegments = NULL;
166     cpw->cpanel.dispauxsegmentsize = 0;
167     cpw->cpanel.numauxsegments = 0;
168     GetInvGC(cpw);
169 }
170 
171 static void
Destroy(w)172 Destroy(w)
173 Widget w;
174 {
175     AuxPanelWidget cpw = (AuxPanelWidget)w;
176 
177     TRACE(("AuxPanel:Destroy()\n"));
178 
179     freeDisplaySegments(cpw);
180     if (cpw->cpanel.invgc != NULL) XtReleaseGC(w, cpw->cpanel.invgc);
181 }
182 
183 static void
Realize(w,mask,value)184 Realize(w, mask, value)
185 Widget w;
186 XtValueMask *mask;
187 XSetWindowAttributes *value;
188 {
189     AuxPanelWidget cpw = (AuxPanelWidget)w;
190     CompositeWidgetClass super = (CompositeWidgetClass)XtClass(w)->core_class.superclass;
191     String params[1];
192     Cardinal num_params;
193 
194     TRACE(("AuxPanel:Realize()\n"));
195 
196     if (cpw->cpanel.displayobj == NULL) {
197 	params[0] = XtClass(w)->core_class.class_name;
198 	num_params = 1;
199 	XtAppErrorMsg(XtWidgetToApplicationContext(w),
200 		      "childError", "number", "WidgetError",
201 		      "%s: has no child (ConvDisplayObject)",
202 		      params, &num_params);
203     }
204 
205     if (cpw->cpanel.cursor != None) {
206 	*mask |= CWCursor;
207 	value->cursor = cpw->cpanel.cursor;
208     }
209 
210     (*super->core_class.realize)(w, mask, value);
211 }
212 
213 /* ARGSUSED */
214 static void
Redisplay(w,ev,region)215 Redisplay(w, ev, region)
216 Widget w;
217 XEvent *ev;
218 Region region;
219 {
220     AuxPanelWidget cpw = (AuxPanelWidget)w;
221     XExposeEvent *event = (XExposeEvent *)ev;
222     DisplaySegment *dseg;
223     int cheight, hspace, vspace;
224     int x, i;
225 
226     TRACE(("AuxPanel:Redisplay()\n"));
227 
228     cheight = cpw->cpanel.fontheight;
229     hspace = cpw->cpanel.hspace;
230     vspace = cpw->cpanel.vspace;
231 
232     if (event->y + event->height < vspace / 2
233 	|| cheight + vspace / 2 < event->y)
234       return;
235 
236     for (i = 0, x = hspace / 2, dseg = cpw->cpanel.dispauxsegments;
237 	 i < cpw->cpanel.numauxsegments ; i++, dseg++) {
238       if (x < event->x + event->width && event->x < x + dseg->width) {
239 	dseg->redrawpos = 0;
240       }
241       else {
242 	dseg->redrawpos = -1; /* $B=q$-D>$9I,MW$,$J$$(B */
243       }
244       x += dseg->width;
245     }
246 
247     UpdateAuxDisplay(cpw);
248 }
249 
250 static void
Resize(w)251 Resize(w)
252 Widget w;
253 {
254     AuxPanelWidget cpw = (AuxPanelWidget)w;
255 
256     TRACE(("AuxPanel:Resize()\n"));
257 
258     Layout(cpw, True, True);
259 }
260 
261 /* ARGSUSED */
262 static Boolean
SetValues(cur,req,wid,args,num_args)263 SetValues(cur, req, wid, args, num_args)
264 Widget cur;
265 Widget req;
266 Widget wid;
267 ArgList args;
268 Cardinal *num_args;
269 {
270     AuxPanelWidget old = (AuxPanelWidget)cur;
271     AuxPanelWidget new = (AuxPanelWidget)wid;
272     Boolean redisplay = False;
273 
274     TRACE(("AuxPanel:SetValues()\n"));
275 
276     if (new->cpanel.displayobj == NULL) return False;
277 
278     if (new->cpanel.foreground != old->cpanel.foreground ||
279 	new->core.background_pixel != old->core.background_pixel) {
280 	XtVaSetValues(new->cpanel.displayobj,
281 		      XtNforeground, new->cpanel.foreground,
282 		      XtNbackground, new->core.background_pixel,
283 		      NULL);
284 	redisplay = True;
285     }
286 
287     if (new->cpanel.numauxsegments > 0 ||
288 	new->cpanel.hspace != old->cpanel.hspace ||
289 	new->cpanel.vspace != old->cpanel.vspace ||
290 	new->cpanel.defaultwidth != old->cpanel.defaultwidth) {
291 	Layout(new, True, True);
292 	redisplay = True;
293     }
294 
295     if (new->cpanel.cursor != old->cpanel.cursor && XtIsRealized(wid)) {
296 	XDefineCursor(XtDisplay(wid), XtWindow(wid), new->cpanel.cursor);
297     }
298 
299     return redisplay;
300 }
301 
302 static XtGeometryResult
QueryGeometry(w,req,ret)303 QueryGeometry(w, req, ret)
304 Widget w;
305 XtWidgetGeometry *req;
306 XtWidgetGeometry *ret;
307 {
308     Dimension width, height;
309     Dimension owidth, oheight;
310 
311     TRACE(("AuxPanel:QueryGeometry()\n"));
312 
313     ret->request_mode = 0;
314 
315     if ((req->request_mode & (CWWidth | CWHeight)) == 0) return XtGeometryYes;
316 
317     width = (req->request_mode & CWWidth) ? req->width : w->core.width;
318     height = (req->request_mode & CWHeight) ? req->height : w->core.height;
319 
320     owidth = width;
321     oheight = height;
322     ComputeSize((AuxPanelWidget)w,
323 		(req->request_mode & CWWidth) != 0,
324 		(req->request_mode & CWHeight) != 0,
325 		&width, &height);
326     ret->request_mode = CWWidth | CWHeight;
327     ret->width = width;
328     ret->height = height;
329 
330     if (width != owidth || height != oheight) return XtGeometryAlmost;
331 
332     return XtGeometryYes;
333 }
334 
335 static void
InsertChild(w)336 InsertChild(w)
337 Widget w;
338 {
339     AuxPanelWidget cpw = (AuxPanelWidget)XtParent(w);
340     CompositeWidgetClass super = (CompositeWidgetClass)XtClass(cpw)->core_class.superclass;
341     String params[1];
342     Cardinal num_params;
343 
344     TRACE(("AuxPanel:InsertChild()\n"));
345 
346     if (!XtIsSubclass(w, convDisplayObjectClass)) {
347 	params[0] = XtClass(cpw)->core_class.class_name;
348 	num_params = 1;
349 	XtAppErrorMsg(XtWidgetToApplicationContext(w),
350 		      "childError", "class", "WidgetError",
351 		      "%s: child must be subclass of ConvDisplayObject",
352 		      params, &num_params);
353     }
354     if (cpw->composite.num_children != 0) {
355 	params[0] = XtClass(cpw)->core_class.class_name;
356 	num_params = 1;
357 	XtAppErrorMsg(XtWidgetToApplicationContext(w),
358 		      "childError", "number", "WidgetError",
359 		      "%s: can only take one child",
360 		      params, &num_params);
361     }
362 
363     (*super->composite_class.insert_child)(w);
364 
365     cpw->cpanel.displayobj = w;
366     cpw->cpanel.fontheight = CDLineHeight(w, (Position *)NULL);
367 
368 #ifdef notdef
369     {
370     Pixel fg, bg;
371     XtVaGetValues(w, XtNforeground, &fg, XtNbackground, &bg, NULL);
372     GetInvGC(cpw, fg, bg);
373     }
374 #endif
375 
376     if (cpw->cpanel.numauxsegments > 0) {
377 	Layout(cpw, cpw->core.width == 0, cpw->core.height == 0);
378     }
379 }
380 
381 static void
GetInvGC(cpw)382 GetInvGC(cpw)
383 AuxPanelWidget cpw;
384 {
385     XGCValues values;
386 
387     TRACE(("AuxPanel:GetInvGC()\n"));
388 
389     values.function = GXinvert;
390     values.plane_mask = cpw->cpanel.foreground ^ cpw->core.background_pixel;
391     cpw->cpanel.invgc = XtGetGC((Widget)cpw, GCFunction|GCPlaneMask, &values);
392 }
393 
394 /* ARGSUSED */
395 static void
ComputeSize(cpw,resizex,resizey,width_inout,height_inout)396 ComputeSize(cpw, resizex, resizey, width_inout, height_inout)
397 AuxPanelWidget cpw;
398 int resizex;
399 int resizey;
400 Dimension *width_inout;
401 Dimension *height_inout;
402 {
403     int width, height;
404     int i, minwidth = 0;
405     DisplaySegment *dseg = cpw->cpanel.dispauxsegments;
406 
407 
408     TRACE(("AuxPanel:ComputeSize()\n"));
409 
410     if (cpw->cpanel.displayobj == NULL) return;
411 
412     width = *width_inout;
413     height = *height_inout;
414 
415     for (i = 0 ; i < cpw->cpanel.numauxsegments ; i++, dseg++) {
416       minwidth += CDStringWidth(cpw->cpanel.displayobj, &dseg->seg, 0, -1);
417     }
418     minwidth += cpw->cpanel.hspace * 2;
419     if (resizex) {
420       width = minwidth;
421     } else {
422       width = (cpw->core.width < minwidth) ? minwidth : cpw->core.width;
423     }
424     height = cpw->cpanel.fontheight + cpw->cpanel.vspace;
425     *width_inout = width;
426     *height_inout = height;
427 }
428 
429 static void
Layout(cpw,resizex,resizey)430 Layout(cpw, resizex, resizey)
431 AuxPanelWidget cpw;
432 int resizex;
433 int resizey;
434 {
435     Dimension width, height;
436     Dimension owidth, oheight;
437     XtGeometryResult re;
438 
439     TRACE(("AuxPanel:Layout()\n"));
440 
441     if (cpw->cpanel.displayobj == NULL) return;
442 
443     width = cpw->core.width;
444     height = cpw->core.height;
445     ComputeSize(cpw, resizex, resizey, &width, &height);
446     if (width != cpw->core.width || height != cpw->core.height) {
447 	owidth = width;
448 	oheight = height;
449 	re = XtMakeResizeRequest((Widget)cpw, owidth, oheight,
450 				 &width, &height);
451 	switch (re) {
452 	case XtGeometryYes:
453 	  /* no problem */
454 	  break;
455 	}
456     }
457 }
458 
459 /*- allocDisplaySegments: prepare specified number of display segments -*/
460 static void
allocDisplaySegments(cpw,n)461 allocDisplaySegments(cpw, n)
462 AuxPanelWidget cpw;
463 Cardinal n;
464 {
465   if (cpw->cpanel.dispauxsegmentsize > n) return;
466   n = ((n + 3) / 4) * 4 ;
467   if (cpw->cpanel.dispauxsegments == NULL) {
468     cpw->cpanel.dispauxsegments =
469       (DisplaySegment *)XtCalloc(n, sizeof(DisplaySegment));
470   } else {
471     cpw->cpanel.dispauxsegments =
472       (DisplaySegment *)XtRealloc((char *)cpw->cpanel.dispauxsegments,
473 				  n * sizeof(DisplaySegment));
474     bzero((char *)(cpw->cpanel.dispauxsegments + cpw->cpanel.numauxsegments),
475 	  (n - cpw->cpanel.numauxsegments) * sizeof(DisplaySegment));
476   }
477   cpw->cpanel.dispauxsegmentsize = n;
478 }
479 
480 /*- freeDisplaySegments: free display segments -*/
481 static void
freeDisplaySegments(cpw)482 freeDisplaySegments(cpw)
483 AuxPanelWidget cpw;
484 {
485   Cardinal i;
486   DisplaySegment *dseg = cpw->cpanel.dispauxsegments;
487 
488   for (i = 0 ; i < cpw->cpanel.dispauxsegmentsize ; i++, dseg++) {
489     if (dseg->seg.data != NULL) XtFree(dseg->seg.data);
490   }
491   XtFree((char *)cpw->cpanel.dispauxsegments);
492   cpw->cpanel.dispauxsegments = (DisplaySegment *)0;
493   cpw->cpanel.dispauxsegmentsize = 0;
494 }
495 
496 /*- copyString: copy ICString -*/
497 static void
copyString(from,to)498 copyString(from, to)
499 ICString *from;
500 ICString *to;
501 {
502   if (to->data != NULL) XtFree(to->data);
503   *to = *from;
504   to->data = XtMalloc(to->nbytes);
505   (void)bcopy(from->data, to->data, to->nbytes);
506 }
507 
508 static void
UpdateAuxDisplay(cpw)509 UpdateAuxDisplay(cpw)
510 AuxPanelWidget cpw;
511 {
512   Widget dispobj = cpw->cpanel.displayobj;
513   DisplaySegment *dseg;
514   int hspace, vspace;
515   int x, y;
516   Cardinal i;
517 
518   if (dispobj == NULL) return;
519 
520   hspace = cpw->cpanel.hspace;
521   vspace = cpw->cpanel.vspace;
522 
523   x = hspace / 2;
524   y = vspace / 2;
525 
526   for (i = 0, dseg = cpw->cpanel.dispauxsegments;
527        i < cpw->cpanel.numauxsegments ; i++, dseg++) {
528     if (dseg->redrawpos >= 0) {
529       int offset = 0;
530       int idx = dseg->redrawpos;
531 
532       if (dseg->width == 0) {
533 	dseg->width = CDStringWidth(dispobj, &dseg->seg, 0, -1);
534       }
535       if (idx > 0) {
536 	offset = CDStringWidth(dispobj, &dseg->seg, 0, idx);
537       }
538       CDDrawString(dispobj, (Widget)cpw, &dseg->seg, 0, -1, x + offset, y);
539     }
540     x += dseg->width;
541   }
542   return;
543 }
544 
545 /*
546  * Public Functions
547  */
548 
549 /* ARGSUSED */
550 void
APanelStart(w,segments,nseg,curseg,cursorpos)551 APanelStart(w, segments, nseg, curseg, cursorpos)
552 Widget w;
553 ICString *segments;
554 Cardinal nseg, curseg, cursorpos;
555 {
556     AuxPanelWidget cpw = (AuxPanelWidget)w;
557     Cardinal i;
558     DisplaySegment *dseg;
559 
560     cpw->cpanel.numauxsegments = nseg;
561     allocDisplaySegments(cpw, nseg);
562     for (i = 0, dseg = cpw->cpanel.dispauxsegments ; i < nseg ; i++, dseg++) {
563       copyString(segments +i, &dseg->seg);
564       dseg->redrawpos = 0;
565       dseg->width = 0;
566     }
567     Layout(cpw, True, True);
568     if (XtIsRealized(w)) XClearWindow(XtDisplay(w), XtWindow(w));
569     return;
570 }
571 
572 void
APanelEnd(w)573 APanelEnd(w)
574 Widget w;
575 {
576   AuxPanelWidget cpw = (AuxPanelWidget)w;
577 
578   cpw->cpanel.numauxsegments = 0;
579   return;
580 }
581 
582 /* ARGSUSED */
583 void
APanelChange(w,segments,nseg,curseg,cursorpos)584 APanelChange(w, segments, nseg, curseg, cursorpos)
585 Widget w;
586 ICString *segments;
587 Cardinal nseg, curseg, cursorpos;
588 {
589   AuxPanelWidget cpw = (AuxPanelWidget)w;
590   Cardinal i;
591   DisplaySegment *dseg;
592 
593   cpw->cpanel.numauxsegments = nseg;
594   allocDisplaySegments(cpw, nseg);
595   for (i = 0, dseg = cpw->cpanel.dispauxsegments ; i < nseg ; i++, dseg++) {
596     /* $BA4=q$-49$($K$J$C$F$7$^$&!#(BICCompareSegment $B$,;H$($k$J$i(B
597        $B;H$$$?$$$N$@$,!#(B */
598     copyString(segments +i, &dseg->seg);
599     dseg->redrawpos = 0;
600     dseg->width = 0;
601   }
602   Layout(cpw, False, False);
603   if (XtIsRealized(w)) XClearWindow(XtDisplay(w), XtWindow(w));
604   UpdateAuxDisplay(cpw);
605   return;
606 }
607