Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / nvi / motif_l / xtabbed.c
blobed511cb5b03abdc1b6fef2be29373d118888047a
1 /* $NetBSD$ */
3 /* ***********************************************************************
4 * This module implements a motif tabbed window widget.
5 * The source is copied from the Free Widget Foundation
6 * This file is divided into thse parts
7 * o - Conversion routines for the X resource manager
8 * o - Routines for drawing rotated text
9 * o - A motif widget for tabbed windows
10 * o - A driver for the above in the flavor of the xt utilities module
11 * ***********************************************************************
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <Xm/Xm.h>
19 #include <Xm/Form.h>
20 #include <Xm/RowColumn.h>
21 #include <X11/StringDefs.h>
22 #include <X11/IntrinsicP.h>
23 #if defined(VMS_HOST)
24 #include <DECW$INCLUDE/shape.h>
25 #else
26 #include <X11/extensions/shape.h>
27 #endif
28 #include <X11/Xlib.h>
29 #include <X11/Xutil.h>
30 #include <X11/Xatom.h>
31 #include <math.h>
34 /* ***********************************************************************
35 * "rotated.h"
36 * ***********************************************************************
39 /* ************************************************************************ */
42 /* Header file for the `xvertext 5.0' routines.
44 Copyright (c) 1993 Alan Richardson (mppa3@uk.ac.sussex.syma) */
47 /* ************************************************************************ */
49 #ifndef _XVERTEXT_INCLUDED_
50 #define _XVERTEXT_INCLUDED_
53 #define XV_VERSION 5.0
54 #define XV_COPYRIGHT \
55 "xvertext routines Copyright (c) 1993 Alan Richardson"
58 /* ---------------------------------------------------------------------- */
61 /* text alignment */
63 #define NONE 0
64 #define TLEFT 1
65 #define TCENTRE 2
66 #define TRIGHT 3
67 #define MLEFT 4
68 #define MCENTRE 5
69 #define MRIGHT 6
70 #define BLEFT 7
71 #define BCENTRE 8
72 #define BRIGHT 9
75 /* ---------------------------------------------------------------------- */
77 /* this shoulf be C++ compliant, thanks to
78 vlp@latina.inesc.pt (Vasco Lopes Paulo) */
80 #if defined(__cplusplus) || defined(c_plusplus)
82 extern "C" {
83 static float XRotVersion(char*, int);
84 static void XRotSetMagnification(float);
85 static void XRotSetBoundingBoxPad(int);
86 static int XRotDrawString(Display*, XFontStruct*, float,
87 Drawable, GC, int, int, char*);
88 static int XRotDrawImageString(Display*, XFontStruct*, float,
89 Drawable, GC, int, int, char*);
90 static int XRotDrawAlignedString(Display*, XFontStruct*, float,
91 Drawable, GC, int, int, char*, int);
92 static int XRotDrawAlignedImageString(Display*, XFontStruct*, float,
93 Drawable, GC, int, int, char*, int);
94 static XPoint *XRotTextExtents(Display*, XFontStruct*, float,
95 int, int, char*, int);
98 #else
100 static float XRotVersion(char *str, int n);
101 static void XRotSetMagnification(float m);
102 static void XRotSetBoundingBoxPad(int p);
103 static int XRotDrawString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *str);
104 static int XRotDrawImageString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *str);
105 static int XRotDrawAlignedString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text, int align);
106 static int XRotDrawAlignedImageString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text, int align);
107 static XPoint *XRotTextExtents(Display *dpy, XFontStruct *font, float angle, int x, int y, char *text, int align);
109 #endif /* __cplusplus */
111 /* ---------------------------------------------------------------------- */
114 #endif /* _XVERTEXT_INCLUDED_ */
119 /* ***********************************************************************
120 * "strarray.h"
121 * ***********************************************************************
124 #ifndef _strarray_h_
125 #define _strarray_h_
127 StringArray
128 ===========
129 The type |StringArray| represents an array of |String|s, with the
130 proviso that by convention the last member of a |StringArray| is
131 always a |NULL| pointer. There is a converter that can construct a
132 |StringArray| from a single string.
135 cvtStringToStringArray
136 ======================
137 The converter from |String| to |StringArray| makes a copy of the
138 passed string and then replaces all occurences of the delimiter
139 with a nul byte. The |StringArray| is filled with pointers to the
140 parts of the string.
142 The delimiter character is the first character in the string.
145 newStringArray
146 ==============
147 The function |newStringArray| makes a copy of a |StringArray|. It
148 allocates new space for the array itself and for the strings that
149 it contains.
152 freeStringArray
153 ===============
154 |freeStringArray| deallocates the array and all strings it
155 contains. Note that this works for StringArrays produced with
156 |newStringArray|, but not for those created by
157 |cvtStringToStringArray|!
162 typedef String * StringArray;
164 static Boolean cvtStringToStringArray(
165 #if NeedFunctionPrototypes
166 Display *display,
167 XrmValuePtr args,
168 Cardinal *num_args,
169 XrmValuePtr from,
170 XrmValuePtr to,
171 XtPointer *converter_data
172 #endif
176 StringArray newStringArray(
177 #if NeedFunctionPrototypes
178 StringArray a
179 #endif
183 void freeStringArray(
184 #if NeedFunctionPrototypes
185 StringArray a
186 #endif
190 #endif /* _strarray_h_ */
193 /* ***********************************************************************
194 * "XmTabs.h"
195 * ***********************************************************************
198 /* Generated by wbuild from "XmTabs.w"
199 ** (generator version Revision: 8.5 of Date: 2001/06/25 15:19:28)
201 #ifndef _XmTabs_H_
202 #define _XmTabs_H_
203 typedef enum {
204 XfwfUpTabs, XfwfDownTabs, XfwfLeftTabs, XfwfRightTabs,
205 } TabsOrientation;
207 #ifndef XtNorientation
208 #define XtNorientation "orientation"
209 #endif
210 #ifndef XtCOrientation
211 #define XtCOrientation "Orientation"
212 #endif
213 #ifndef XtRTabsOrientation
214 #define XtRTabsOrientation "TabsOrientation"
215 #endif
217 #ifndef XtNlefttabs
218 #define XtNlefttabs "lefttabs"
219 #endif
220 #ifndef XtCLefttabs
221 #define XtCLefttabs "Lefttabs"
222 #endif
223 #ifndef XtRInt
224 #define XtRInt "Int"
225 #endif
227 #ifndef XtNrighttabs
228 #define XtNrighttabs "righttabs"
229 #endif
230 #ifndef XtCRighttabs
231 #define XtCRighttabs "Righttabs"
232 #endif
233 #ifndef XtRInt
234 #define XtRInt "Int"
235 #endif
237 #ifndef XtNlabels
238 #define XtNlabels "labels"
239 #endif
240 #ifndef XtCLabels
241 #define XtCLabels "Labels"
242 #endif
243 #ifndef XtRStringArray
244 #define XtRStringArray "StringArray"
245 #endif
247 #ifndef XtNtabWidthPercentage
248 #define XtNtabWidthPercentage "tabWidthPercentage"
249 #endif
250 #ifndef XtCTabWidthPercentage
251 #define XtCTabWidthPercentage "TabWidthPercentage"
252 #endif
253 #ifndef XtRInt
254 #define XtRInt "Int"
255 #endif
257 #ifndef XtNcornerwidth
258 #define XtNcornerwidth "cornerwidth"
259 #endif
260 #ifndef XtCCornerwidth
261 #define XtCCornerwidth "Cornerwidth"
262 #endif
263 #ifndef XtRCardinal
264 #define XtRCardinal "Cardinal"
265 #endif
267 #ifndef XtNcornerheight
268 #define XtNcornerheight "cornerheight"
269 #endif
270 #ifndef XtCCornerheight
271 #define XtCCornerheight "Cornerheight"
272 #endif
273 #ifndef XtRCardinal
274 #define XtRCardinal "Cardinal"
275 #endif
277 #ifndef XtNtextmargin
278 #define XtNtextmargin "textmargin"
279 #endif
280 #ifndef XtCTextmargin
281 #define XtCTextmargin "Textmargin"
282 #endif
283 #ifndef XtRInt
284 #define XtRInt "Int"
285 #endif
287 #ifndef XtNtabcolor
288 #define XtNtabcolor "tabcolor"
289 #endif
290 #ifndef XtCTabcolor
291 #define XtCTabcolor "Tabcolor"
292 #endif
293 #ifndef XtRPixel
294 #define XtRPixel "Pixel"
295 #endif
297 #ifndef XtNfont
298 #define XtNfont "font"
299 #endif
300 #ifndef XtCFont
301 #define XtCFont "Font"
302 #endif
303 #ifndef XtRFontStruct
304 #define XtRFontStruct "FontStruct"
305 #endif
307 #ifndef XtNactivateCallback
308 #define XtNactivateCallback "activateCallback"
309 #endif
310 #ifndef XtCActivateCallback
311 #define XtCActivateCallback "ActivateCallback"
312 #endif
313 #ifndef XtRCallback
314 #define XtRCallback "Callback"
315 #endif
317 typedef struct _XmTabsClassRec *XmTabsWidgetClass;
318 typedef struct _XmTabsRec *XmTabsWidget;
319 #endif /*_XmTabs_H_*/
322 /* ***********************************************************************
323 * "XmTabsP.h"
324 * ***********************************************************************
327 /* Generated by wbuild from "XmTabs.w"
328 ** (generator version Revision: 8.5 of Date: 2001/06/25 15:19:28)
330 #ifndef _XmTabsP_H_
331 #define _XmTabsP_H_
333 /* raz modified 22 Jul 96 for bluestone */
334 #include <Xm/XmP.h>
335 #if ! defined(MGR_ShadowThickness)
336 #include <Xm/ManagerP.h>
337 #endif
339 typedef void (*border_highlight_Proc)(
340 #if NeedFunctionPrototypes
341 void
342 #endif
344 #define XtInherit_border_highlight ((border_highlight_Proc) _XtInherit)
345 typedef void (*border_unhighlight_Proc)(
346 #if NeedFunctionPrototypes
347 void
348 #endif
350 #define XtInherit_border_unhighlight ((border_unhighlight_Proc) _XtInherit)
351 typedef struct {
352 /* Constraint resources */
353 /* Private constraint variables */
354 int dummy;
355 } XmTabsConstraintPart;
357 typedef struct _XmTabsConstraintRec {
358 XmManagerConstraintPart xmManager;
359 XmTabsConstraintPart xmTabs;
360 } XmTabsConstraintRec;
363 typedef struct {
364 /* methods */
365 border_highlight_Proc border_highlight;
366 border_unhighlight_Proc border_unhighlight;
367 /* class variables */
368 } XmTabsClassPart;
370 typedef struct _XmTabsClassRec {
371 CoreClassPart core_class;
372 CompositeClassPart composite_class;
373 ConstraintClassPart constraint_class;
374 XmManagerClassPart xmManager_class;
375 XmTabsClassPart xmTabs_class;
376 } XmTabsClassRec;
378 typedef struct {
379 /* resources */
380 TabsOrientation orientation;
381 int lefttabs;
382 int righttabs;
383 StringArray labels;
384 int tabWidthPercentage;
385 Cardinal cornerwidth;
386 Cardinal cornerheight;
387 int textmargin;
388 Pixel tabcolor;
389 XFontStruct * font;
390 XtCallbackList activateCallback;
391 /* private state */
392 GC textgc;
393 GC topgc;
394 GC bottomgc;
395 GC backgc;
396 GC fillgc;
397 int * tabwidths;
398 int * offsets;
399 } XmTabsPart;
401 typedef struct _XmTabsRec {
402 CorePart core;
403 CompositePart composite;
404 ConstraintPart constraint;
405 XmManagerPart xmManager;
406 XmTabsPart xmTabs;
407 } XmTabsRec;
409 #endif /* _XmTabsP_H_ */
412 /* ***********************************************************************
413 * A motif widget for tabbed windows
414 * ***********************************************************************
417 static void activate(
418 #if NeedFunctionPrototypes
419 Widget,XEvent*,String*,Cardinal*
420 #endif
423 static XtActionsRec actionsList[] = {
424 {"activate", activate},
427 static char defaultTranslations[] = "\
428 <Btn1Down>,<Btn1Up>: activate() \n\
430 static void _resolve_inheritance(
431 #if NeedFunctionPrototypes
432 WidgetClass
433 #endif
435 static void class_initialize(
436 #if NeedFunctionPrototypes
437 void
438 #endif
440 static void initialize(
441 #if NeedFunctionPrototypes
442 Widget ,Widget,ArgList ,Cardinal *
443 #endif
445 static Boolean set_values(
446 #if NeedFunctionPrototypes
447 Widget ,Widget ,Widget,ArgList ,Cardinal *
448 #endif
450 static void realize(
451 #if NeedFunctionPrototypes
452 Widget,XtValueMask *,XSetWindowAttributes *
453 #endif
455 static void resize(
456 #if NeedFunctionPrototypes
457 Widget
458 #endif
460 static void expose(
461 #if NeedFunctionPrototypes
462 Widget,XEvent *,Region
463 #endif
465 static void border_highlight(
466 #if NeedFunctionPrototypes
467 void
468 #endif
470 static void border_unhighlight(
471 #if NeedFunctionPrototypes
472 void
473 #endif
475 static void destroy(
476 #if NeedFunctionPrototypes
477 Widget
478 #endif
480 #define min(a, b) ((a )<(b )?(a ):(b ))
483 #define abs(x) ((x )<0 ?-(x ):(x ))
486 static void compute_tabsizes(
487 #if NeedFunctionPrototypes
488 Widget
489 #endif
491 static void comp_hor_tab_shape(
492 #if NeedFunctionPrototypes
493 Widget,int ,XPoint p[12],int *,int *,int *
494 #endif
496 static void comp_ver_tab_shape(
497 #if NeedFunctionPrototypes
498 Widget,int ,XPoint p[12],int *,int *,int *
499 #endif
501 static void draw_border(
502 #if NeedFunctionPrototypes
503 Widget,XPoint poly[12]
504 #endif
506 static void draw_hor_tab(
507 #if NeedFunctionPrototypes
508 Widget,Region ,int
509 #endif
511 static void draw_ver_tab(
512 #if NeedFunctionPrototypes
513 Widget,Region ,int
514 #endif
516 static void create_topgc(
517 #if NeedFunctionPrototypes
518 Widget
519 #endif
521 static void create_bottomgc(
522 #if NeedFunctionPrototypes
523 Widget
524 #endif
526 static void create_textgc(
527 #if NeedFunctionPrototypes
528 Widget
529 #endif
531 static void create_fillgc(
532 #if NeedFunctionPrototypes
533 Widget
534 #endif
536 static void create_backgc(
537 #if NeedFunctionPrototypes
538 Widget
539 #endif
541 static void copy_bg(
542 #if NeedFunctionPrototypes
543 Widget,int ,XrmValue *
544 #endif
546 static void set_shape(
547 #if NeedFunctionPrototypes
548 Widget
549 #endif
551 #define done(type, value) do {\
552 if (to->addr != NULL) {\
553 if (to->size < sizeof(type)) {\
554 to->size = sizeof(type);\
555 return False;\
557 *(type*)(to->addr) = (value);\
558 } else {\
559 static type static_val;\
560 static_val = (value);\
561 to->addr = (XtPointer)&static_val;\
563 to->size = sizeof(type);\
564 return True;\
565 }while (0 )
568 static Boolean cvtStringToTabsOrientation(
569 #if NeedFunctionPrototypes
570 Display *,XrmValuePtr ,Cardinal *,XrmValuePtr ,XrmValuePtr ,XtPointer *
571 #endif
573 static Boolean cvtTabsOrientationToString(
574 #if NeedFunctionPrototypes
575 Display *,XrmValuePtr ,Cardinal *,XrmValuePtr ,XrmValuePtr ,XtPointer *
576 #endif
578 /*ARGSUSED*/
579 #if NeedFunctionPrototypes
580 static void compute_tabsizes(Widget self)
581 #else
582 static void compute_tabsizes(self)Widget self;
583 #endif
585 int maxwd, basewidth, delta, i, n = ((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs + 1;
586 int sum, len, h, length, breadth, shad = ((XmTabsWidget)self)->xmManager.shadow_thickness;
588 if (((XmTabsWidget)self)->xmTabs.offsets) XtFree((XtPointer) ((XmTabsWidget)self)->xmTabs.offsets);
589 if (((XmTabsWidget)self)->xmTabs.tabwidths) XtFree((XtPointer) ((XmTabsWidget)self)->xmTabs.tabwidths);
590 ((XmTabsWidget)self)->xmTabs.offsets = (XtPointer) XtMalloc(n * sizeof(*((XmTabsWidget)self)->xmTabs.offsets));
591 ((XmTabsWidget)self)->xmTabs.tabwidths = (XtPointer) XtMalloc(n * sizeof(*((XmTabsWidget)self)->xmTabs.tabwidths));
593 if (((XmTabsWidget)self)->xmTabs.orientation == XfwfUpTabs || ((XmTabsWidget)self)->xmTabs.orientation == XfwfDownTabs) {
594 length = ((XmTabsWidget)self)->core.width;
595 breadth = ((XmTabsWidget)self)->core.height;
596 } else {
597 length = ((XmTabsWidget)self)->core.height;
598 breadth = ((XmTabsWidget)self)->core.width;
600 if (((XmTabsWidget)self)->xmTabs.tabWidthPercentage != 0) { /* Fixed width tabs */
601 basewidth = ((XmTabsWidget)self)->xmTabs.tabWidthPercentage * length/100;
602 if (n > 1) delta = (length - basewidth)/(((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs);
603 for (i = 0; i < n; i++) {
604 ((XmTabsWidget)self)->xmTabs.tabwidths[i] = basewidth;
605 ((XmTabsWidget)self)->xmTabs.offsets[i] = i * delta;
607 } else if (((XmTabsWidget)self)->xmTabs.labels == NULL) { /* Empty tabs */
608 basewidth = length/n;
609 delta = (length - basewidth)/(((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs);
610 for (i = 0; i < n; i++) {
611 ((XmTabsWidget)self)->xmTabs.tabwidths[i] = basewidth;
612 ((XmTabsWidget)self)->xmTabs.offsets[i] = i * delta;
614 } else { /* Variable width tabs */
615 sum = 0;
616 h = 2 * (((XmTabsWidget)self)->xmTabs.cornerwidth + shad + ((XmTabsWidget)self)->xmTabs.textmargin);
617 maxwd = length - n * (shad + ((XmTabsWidget)self)->xmTabs.textmargin);
618 for (i = 0; i < n; i++) {
619 len = strlen(((XmTabsWidget)self)->xmTabs.labels[i]);
620 ((XmTabsWidget)self)->xmTabs.tabwidths[i] = min(maxwd, XTextWidth(((XmTabsWidget)self)->xmTabs.font,((XmTabsWidget)self)->xmTabs.labels[i],len) + h);
621 sum += ((XmTabsWidget)self)->xmTabs.tabwidths[i];
623 ((XmTabsWidget)self)->xmTabs.offsets[0] = 0;
624 if (length >= sum)
625 delta = (length - sum)/(n - 1); /* Between tabs */
626 else
627 delta = -((sum - length + n - 2)/(n - 1)); /* Round down! */
628 for (i = 1; i < n; i++)
629 ((XmTabsWidget)self)->xmTabs.offsets[i] = ((XmTabsWidget)self)->xmTabs.offsets[i-1] + ((XmTabsWidget)self)->xmTabs.tabwidths[i-1] + delta;
632 /*ARGSUSED*/
633 #if NeedFunctionPrototypes
634 static void comp_hor_tab_shape(Widget self,int i,XPoint p[12],int * x0,int * x1,int * midy)
635 #else
636 static void comp_hor_tab_shape(self,i,p,x0,x1,midy)Widget self;int i;XPoint p[12];int * x0;int * x1;int * midy;
637 #endif
639 int shad = ((XmTabsWidget)self)->xmManager.shadow_thickness;
640 int k = min(((XmTabsWidget)self)->xmTabs.cornerheight, (((XmTabsWidget)self)->core.height - shad)/2);
642 * 4 o-------------o 5
643 * / \
644 * 3 o o 6
645 * | |
646 * 2 o o 7
647 * 1 / \ 8
648 * 0 o--------o o--------o 9
649 * 11 o---------------------------------------o 10
651 * 11 o---------------------------------------o 10
652 * 0 o--------o o--------o 9
653 * 1 \ / 8
654 * 2 o o 7
655 * | |
656 * 3 o o 6
657 * \ /
658 * 4 o-------------o 5
660 p[0].x = 0;
661 p[1].x = ((XmTabsWidget)self)->xmTabs.offsets[i];
662 p[2].x = ((XmTabsWidget)self)->xmTabs.offsets[i] + ((XmTabsWidget)self)->xmTabs.cornerwidth;
663 p[3].x = ((XmTabsWidget)self)->xmTabs.offsets[i] + ((XmTabsWidget)self)->xmTabs.cornerwidth;
664 p[4].x = ((XmTabsWidget)self)->xmTabs.offsets[i] + 2 * ((XmTabsWidget)self)->xmTabs.cornerwidth;
665 p[5].x = ((XmTabsWidget)self)->xmTabs.offsets[i] + ((XmTabsWidget)self)->xmTabs.tabwidths[i] - 2 * ((XmTabsWidget)self)->xmTabs.cornerwidth;
666 p[6].x = ((XmTabsWidget)self)->xmTabs.offsets[i] + ((XmTabsWidget)self)->xmTabs.tabwidths[i] - ((XmTabsWidget)self)->xmTabs.cornerwidth;
667 p[7].x = ((XmTabsWidget)self)->xmTabs.offsets[i] + ((XmTabsWidget)self)->xmTabs.tabwidths[i] - ((XmTabsWidget)self)->xmTabs.cornerwidth;
668 p[8].x = ((XmTabsWidget)self)->xmTabs.offsets[i] + ((XmTabsWidget)self)->xmTabs.tabwidths[i];
669 p[9].x = ((XmTabsWidget)self)->core.width;
670 p[10].x = ((XmTabsWidget)self)->core.width;
671 p[11].x = 0;
673 if (((XmTabsWidget)self)->xmTabs.orientation == XfwfUpTabs) {
674 p[0].y = ((XmTabsWidget)self)->core.height - shad;
675 p[1].y = ((XmTabsWidget)self)->core.height - shad;
676 p[2].y = ((XmTabsWidget)self)->core.height - shad - k;
677 p[3].y = k;
678 p[4].y = 0;
679 p[5].y = 0;
680 p[6].y = k;
681 p[7].y = ((XmTabsWidget)self)->core.height - shad - k;
682 p[8].y = ((XmTabsWidget)self)->core.height - shad;
683 p[9].y = ((XmTabsWidget)self)->core.height - shad;
684 p[10].y = ((XmTabsWidget)self)->core.height;
685 p[11].y = ((XmTabsWidget)self)->core.height;
686 } else {
687 p[0].y = shad;
688 p[1].y = shad;
689 p[2].y = shad + k;
690 p[3].y = ((XmTabsWidget)self)->core.height - k;
691 p[4].y = ((XmTabsWidget)self)->core.height;
692 p[5].y = ((XmTabsWidget)self)->core.height;
693 p[6].y = ((XmTabsWidget)self)->core.height - k;
694 p[7].y = shad + k;
695 p[8].y = shad;
696 p[9].y = shad;
697 p[10].y = 0;
698 p[11].y = 0;
700 *x0 = p[4].x;
701 *x1 = p[5].x;
702 *midy = (p[1].y + p[4].y)/2;
704 /*ARGSUSED*/
705 #if NeedFunctionPrototypes
706 static void comp_ver_tab_shape(Widget self,int i,XPoint p[12],int * y0,int * y1,int * midx)
707 #else
708 static void comp_ver_tab_shape(self,i,p,y0,y1,midx)Widget self;int i;XPoint p[12];int * y0;int * y1;int * midx;
709 #endif
711 int shad = ((XmTabsWidget)self)->xmManager.shadow_thickness;
712 int k = min(((XmTabsWidget)self)->xmTabs.cornerheight, (((XmTabsWidget)self)->core.width - shad)/2);
714 * 0 o_o 11 11 o_o 0
715 * | | | |
716 * 1 o | | o 1
717 * 3 2/ | | \2 3
718 * o-o | | o-o
719 * / | | \
720 * 4 o | | o 4
721 * | | | |
722 * 5 o | | o 5
723 * \ | | /
724 * o-o | | o-o
725 * 6 7\ | | /7 6
726 * 8 o | | o 8
727 * | | | |
728 * 9 o_o 10 10 o_o 9
730 if (((XmTabsWidget)self)->xmTabs.orientation == XfwfLeftTabs) {
731 p[0].x = ((XmTabsWidget)self)->core.width - shad;
732 p[1].x = ((XmTabsWidget)self)->core.width - shad;
733 p[2].x = ((XmTabsWidget)self)->core.width - shad - k;
734 p[3].x = k;
735 p[4].x = 0;
736 p[5].x = 0;
737 p[6].x = k;
738 p[7].x = ((XmTabsWidget)self)->core.width - shad - k;
739 p[8].x = ((XmTabsWidget)self)->core.width - shad;
740 p[9].x = ((XmTabsWidget)self)->core.width - shad;
741 p[10].x = ((XmTabsWidget)self)->core.width;
742 p[11].x = ((XmTabsWidget)self)->core.width;
743 } else {
744 p[0].x = shad;
745 p[1].x = shad;
746 p[2].x = shad + k;
747 p[3].x = ((XmTabsWidget)self)->core.width - k;
748 p[4].x = ((XmTabsWidget)self)->core.width;
749 p[5].x = ((XmTabsWidget)self)->core.width;
750 p[6].x = ((XmTabsWidget)self)->core.width - k;
751 p[7].x = shad + k;
752 p[8].x = shad;
753 p[9].x = shad;
754 p[10].x = 0;
755 p[11].x = 0;
757 p[0].y = 0;
758 p[1].y = ((XmTabsWidget)self)->xmTabs.offsets[i];
759 p[2].y = ((XmTabsWidget)self)->xmTabs.offsets[i] + ((XmTabsWidget)self)->xmTabs.cornerwidth;
760 p[3].y = ((XmTabsWidget)self)->xmTabs.offsets[i] + ((XmTabsWidget)self)->xmTabs.cornerwidth;
761 p[4].y = ((XmTabsWidget)self)->xmTabs.offsets[i] + 2 * ((XmTabsWidget)self)->xmTabs.cornerwidth;
762 p[5].y = ((XmTabsWidget)self)->xmTabs.offsets[i] + ((XmTabsWidget)self)->xmTabs.tabwidths[i] - 2 * ((XmTabsWidget)self)->xmTabs.cornerwidth;
763 p[6].y = ((XmTabsWidget)self)->xmTabs.offsets[i] + ((XmTabsWidget)self)->xmTabs.tabwidths[i] - ((XmTabsWidget)self)->xmTabs.cornerwidth;
764 p[7].y = ((XmTabsWidget)self)->xmTabs.offsets[i] + ((XmTabsWidget)self)->xmTabs.tabwidths[i] - ((XmTabsWidget)self)->xmTabs.cornerwidth;
765 p[8].y = ((XmTabsWidget)self)->xmTabs.offsets[i] + ((XmTabsWidget)self)->xmTabs.tabwidths[i];
766 p[9].y = ((XmTabsWidget)self)->core.height;
767 p[10].y = ((XmTabsWidget)self)->core.height;
768 p[11].y = 0;
769 *y0 = p[4].y;
770 *y1 = p[5].y;
771 *midx = (p[1].x + p[4].x)/2;
773 /*ARGSUSED*/
774 #if NeedFunctionPrototypes
775 static void draw_border(Widget self,XPoint poly[12])
776 #else
777 static void draw_border(self,poly)Widget self;XPoint poly[12];
778 #endif
780 Display *dpy = XtDisplay(self);
781 Window win = XtWindow(self);
783 if (((XmTabsWidget)self)->xmTabs.orientation == XfwfUpTabs) {
784 XDrawLines(dpy, win, ((XmTabsWidget)self)->xmTabs.topgc, poly, 6, CoordModeOrigin);
785 XDrawLines(dpy, win, ((XmTabsWidget)self)->xmTabs.bottomgc, poly + 5, 4, CoordModeOrigin);
786 XDrawLines(dpy, win, ((XmTabsWidget)self)->xmTabs.topgc, poly + 8, 2, CoordModeOrigin);
787 } else {
788 XDrawLines(dpy, win, ((XmTabsWidget)self)->xmTabs.bottomgc, poly, 2, CoordModeOrigin);
789 XDrawLines(dpy, win, ((XmTabsWidget)self)->xmTabs.topgc, poly + 1, 4, CoordModeOrigin);
790 XDrawLines(dpy, win, ((XmTabsWidget)self)->xmTabs.bottomgc, poly + 4, 6, CoordModeOrigin);
793 /*ARGSUSED*/
794 #if NeedFunctionPrototypes
795 static void draw_hor_tab(Widget self,Region region,int i)
796 #else
797 static void draw_hor_tab(self,region,i)Widget self;Region region;int i;
798 #endif
800 XPoint p[12];
801 Display *dpy = XtDisplay(self);
802 Window win = XtWindow(self);
803 Region clip;
804 int x0, x1, midy;
806 comp_hor_tab_shape(self, i, p, &x0, &x1, &midy);
807 clip = XPolygonRegion(p, XtNumber(p), WindingRule);
808 if (region) XIntersectRegion(clip, region, clip);
809 if (XEmptyRegion(clip)) return;
811 XSetRegion(dpy, ((XmTabsWidget)self)->xmTabs.textgc, clip);
812 XSetRegion(dpy, ((XmTabsWidget)self)->xmTabs.topgc, clip);
813 XSetRegion(dpy, ((XmTabsWidget)self)->xmTabs.bottomgc, clip);
814 if (i == ((XmTabsWidget)self)->xmTabs.lefttabs) {
815 XSetRegion(dpy, ((XmTabsWidget)self)->xmTabs.backgc, clip);
816 XFillPolygon(dpy, win, ((XmTabsWidget)self)->xmTabs.backgc,
817 p, XtNumber(p), Convex, CoordModeOrigin);
818 } else {
819 XSetRegion(dpy, ((XmTabsWidget)self)->xmTabs.fillgc, clip);
820 XFillPolygon(dpy, win, ((XmTabsWidget)self)->xmTabs.fillgc,
821 p, XtNumber(p), Convex, CoordModeOrigin);
823 if (((XmTabsWidget)self)->xmTabs.labels) {
824 int w, y, x, len = strlen(((XmTabsWidget)self)->xmTabs.labels[i]);
825 y = midy - (((XmTabsWidget)self)->xmTabs.font->ascent + ((XmTabsWidget)self)->xmTabs.font->descent)/2 + ((XmTabsWidget)self)->xmTabs.font->ascent;
826 w = XTextWidth(((XmTabsWidget)self)->xmTabs.font, ((XmTabsWidget)self)->xmTabs.labels[i], len);
827 if (i == ((XmTabsWidget)self)->xmTabs.lefttabs
828 || ((XmTabsWidget)self)->xmTabs.tabWidthPercentage <= 100/(((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs + 1))
829 x = (x0 + x1 - w)/2; /* Centered text */
830 else if (i < ((XmTabsWidget)self)->xmTabs.lefttabs)
831 x = x0 + ((XmTabsWidget)self)->xmTabs.textmargin; /* Left aligned text */
832 else
833 x = x1 - ((XmTabsWidget)self)->xmTabs.textmargin - w; /* Right aligned text */
834 XDrawString(dpy, win, ((XmTabsWidget)self)->xmTabs.textgc, x, y, ((XmTabsWidget)self)->xmTabs.labels[i], len);
836 draw_border(self, p);
837 XDestroyRegion(clip);
839 /*ARGSUSED*/
840 #if NeedFunctionPrototypes
841 static void draw_ver_tab(Widget self,Region region,int i)
842 #else
843 static void draw_ver_tab(self,region,i)Widget self;Region region;int i;
844 #endif
846 Display *dpy = XtDisplay(self);
847 Window win = XtWindow(self);
848 XPoint p[12];
849 Region clip;
850 int y0, y1, midx;
852 comp_ver_tab_shape(self, i, p, &y0, &y1, &midx);
853 clip = XPolygonRegion(p, XtNumber(p), WindingRule);
854 if (region) XIntersectRegion(clip, region, clip);
855 if (XEmptyRegion(clip)) return;
857 XSetRegion(dpy, ((XmTabsWidget)self)->xmTabs.textgc, clip);
858 XSetRegion(dpy, ((XmTabsWidget)self)->xmTabs.topgc, clip);
859 XSetRegion(dpy, ((XmTabsWidget)self)->xmTabs.bottomgc, clip);
860 if (i == ((XmTabsWidget)self)->xmTabs.lefttabs) {
861 XSetRegion(dpy, ((XmTabsWidget)self)->xmTabs.backgc, clip);
862 XFillPolygon(dpy, win, ((XmTabsWidget)self)->xmTabs.backgc,
863 p, XtNumber(p), Convex, CoordModeOrigin);
864 } else {
865 XSetRegion(dpy, ((XmTabsWidget)self)->xmTabs.fillgc, clip);
866 XFillPolygon(dpy, win, ((XmTabsWidget)self)->xmTabs.fillgc,
867 p, XtNumber(p), Convex, CoordModeOrigin);
869 if (((XmTabsWidget)self)->xmTabs.labels) {
870 int y, align;
871 float angle = ((XmTabsWidget)self)->xmTabs.orientation == XfwfLeftTabs ? 90.0 : -90.0;
872 if (i == ((XmTabsWidget)self)->xmTabs.lefttabs
873 || ((XmTabsWidget)self)->xmTabs.tabWidthPercentage <= 100/(((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs + 1)) {
874 y = (y0 + y1)/2;
875 align = MCENTRE;
876 } else if (i < ((XmTabsWidget)self)->xmTabs.lefttabs) {
877 y = y0 + ((XmTabsWidget)self)->xmTabs.textmargin;
878 align = ((XmTabsWidget)self)->xmTabs.orientation == XfwfLeftTabs ? MRIGHT : MLEFT;
879 } else {
880 y = y1 - ((XmTabsWidget)self)->xmTabs.textmargin;
881 align = ((XmTabsWidget)self)->xmTabs.orientation == XfwfLeftTabs ? MLEFT : MRIGHT;
883 XRotDrawAlignedString
884 (dpy, ((XmTabsWidget)self)->xmTabs.font, angle, win, ((XmTabsWidget)self)->xmTabs.textgc, midx, y, ((XmTabsWidget)self)->xmTabs.labels[i], align);
886 draw_border(self, p);
887 XDestroyRegion(clip);
889 /*ARGSUSED*/
890 #if NeedFunctionPrototypes
891 static void create_topgc(Widget self)
892 #else
893 static void create_topgc(self)Widget self;
894 #endif
896 XtGCMask mask = GCForeground | GCLineWidth;
897 XGCValues values;
899 if (((XmTabsWidget)self)->xmTabs.topgc != NULL) XFreeGC(XtDisplay(self), ((XmTabsWidget)self)->xmTabs.topgc);
900 values.foreground = ((XmTabsWidget)self)->xmManager.top_shadow_color;
901 values.line_width = 2 * ((XmTabsWidget)self)->xmManager.shadow_thickness;
902 ((XmTabsWidget)self)->xmTabs.topgc = XCreateGC(XtDisplay(self), RootWindowOfScreen(XtScreen(self)),
903 mask, &values);
905 /*ARGSUSED*/
906 #if NeedFunctionPrototypes
907 static void create_bottomgc(Widget self)
908 #else
909 static void create_bottomgc(self)Widget self;
910 #endif
912 XtGCMask mask = GCForeground | GCLineWidth;
913 XGCValues values;
915 if (((XmTabsWidget)self)->xmTabs.bottomgc != NULL) XFreeGC(XtDisplay(self), ((XmTabsWidget)self)->xmTabs.bottomgc);
916 values.foreground = ((XmTabsWidget)self)->xmManager.bottom_shadow_color;
917 values.line_width = 2 * ((XmTabsWidget)self)->xmManager.shadow_thickness;
918 ((XmTabsWidget)self)->xmTabs.bottomgc = XCreateGC(XtDisplay(self), RootWindowOfScreen(XtScreen(self)),
919 mask, &values);
921 /*ARGSUSED*/
922 #if NeedFunctionPrototypes
923 static void create_textgc(Widget self)
924 #else
925 static void create_textgc(self)Widget self;
926 #endif
928 XtGCMask mask = GCForeground | GCFont;
929 XGCValues values;
931 if (((XmTabsWidget)self)->xmTabs.textgc != NULL) XFreeGC(XtDisplay(self), ((XmTabsWidget)self)->xmTabs.textgc);
932 values.foreground = ((XmTabsWidget)self)->xmManager.foreground;
933 values.font = ((XmTabsWidget)self)->xmTabs.font->fid;
934 ((XmTabsWidget)self)->xmTabs.textgc = XCreateGC(XtDisplay(self), RootWindowOfScreen(XtScreen(self)),
935 mask, &values);
937 /*ARGSUSED*/
938 #if NeedFunctionPrototypes
939 static void create_fillgc(Widget self)
940 #else
941 static void create_fillgc(self)Widget self;
942 #endif
944 XtGCMask mask = GCForeground;
945 XGCValues values;
947 if (((XmTabsWidget)self)->xmTabs.fillgc != NULL) XFreeGC(XtDisplay(self), ((XmTabsWidget)self)->xmTabs.fillgc);
948 values.foreground = ((XmTabsWidget)self)->xmTabs.tabcolor;
949 ((XmTabsWidget)self)->xmTabs.fillgc = XCreateGC(XtDisplay(self), RootWindowOfScreen(XtScreen(self)),
950 mask, &values);
952 /*ARGSUSED*/
953 #if NeedFunctionPrototypes
954 static void create_backgc(Widget self)
955 #else
956 static void create_backgc(self)Widget self;
957 #endif
959 XtGCMask mask = GCForeground;
960 XGCValues values;
962 if (((XmTabsWidget)self)->xmTabs.backgc != NULL) XFreeGC(XtDisplay(self), ((XmTabsWidget)self)->xmTabs.backgc);
963 values.foreground = ((XmTabsWidget)self)->core.background_pixel;
964 ((XmTabsWidget)self)->xmTabs.backgc = XCreateGC(XtDisplay(self), RootWindowOfScreen(XtScreen(self)),
965 mask, &values);
967 /*ARGSUSED*/
968 #if NeedFunctionPrototypes
969 static void copy_bg(Widget self,int offset,XrmValue * value)
970 #else
971 static void copy_bg(self,offset,value)Widget self;int offset;XrmValue * value;
972 #endif
974 value->addr = (XtPointer) &((XmTabsWidget)self)->core.background_pixel;
976 /*ARGSUSED*/
977 #if NeedFunctionPrototypes
978 static void set_shape(Widget self)
979 #else
980 static void set_shape(self)Widget self;
981 #endif
983 int x0, x1, midy, y0, y1, midx, i;
984 Region region, clip;
985 XPoint poly[12];
987 if (! XtIsRealized(self)) return;
989 region = XCreateRegion();
991 switch (((XmTabsWidget)self)->xmTabs.orientation) {
992 case XfwfUpTabs:
993 case XfwfDownTabs:
994 for (i = 0; i <= ((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs; i++) {
995 comp_hor_tab_shape(self, i, poly, &x0, &x1, &midy);
996 clip = XPolygonRegion(poly, XtNumber(poly), WindingRule);
997 XUnionRegion(region, clip, region);
998 XDestroyRegion(clip);
1000 break;
1001 case XfwfLeftTabs:
1002 case XfwfRightTabs:
1003 for (i = 0; i <= ((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs; i++) {
1004 comp_ver_tab_shape(self, i, poly, &y0, &y1, &midx);
1005 clip = XPolygonRegion(poly, XtNumber(poly), WindingRule);
1006 XUnionRegion(region, clip, region);
1007 XDestroyRegion(clip);
1009 break;
1011 XShapeCombineRegion(XtDisplay(self), XtWindow(self), ShapeBounding,
1012 0, 0, region, ShapeSet);
1013 XDestroyRegion(region);
1016 /*ARGSUSED*/
1017 #if NeedFunctionPrototypes
1018 static Boolean cvtStringToTabsOrientation(Display * display,XrmValuePtr args,Cardinal * num_args,XrmValuePtr from,XrmValuePtr to,XtPointer * converter_data)
1019 #else
1020 static Boolean cvtStringToTabsOrientation(display,args,num_args,from,to,converter_data)Display * display;XrmValuePtr args;Cardinal * num_args;XrmValuePtr from;XrmValuePtr to;XtPointer * converter_data;
1021 #endif
1023 TabsOrientation a = XfwfUpTabs;
1024 char *s = (char*) from->addr;
1025 static struct {
1026 char *name;
1027 TabsOrientation orient;
1028 } strings[] = {
1029 { "up", XfwfUpTabs },
1030 { "uptabs", XfwfUpTabs },
1031 { "down", XfwfDownTabs },
1032 { "downtabs", XfwfDownTabs },
1033 { "left", XfwfLeftTabs },
1034 { "lefttabs", XfwfLeftTabs },
1035 { "right", XfwfRightTabs },
1036 { "righttabs", XfwfRightTabs },
1038 int i;
1040 if (*num_args != 0)
1041 XtAppErrorMsg
1042 (XtDisplayToApplicationContext(display),
1043 "cvtStringToTabsOrientation", "wrongParameters", "XtToolkitError",
1044 "String to TabsOrientation conversion needs no arguments",
1045 (String*) NULL, (Cardinal*) NULL);
1047 for (i=0; i<XtNumber(strings); i++)
1048 if ( strcmp( s, strings[i].name ) == 0 ) {
1049 a |= strings[i].orient;
1050 break;
1053 if ( i >= XtNumber(strings) )
1054 XtDisplayStringConversionWarning(display, s, "TabsOrientation");
1055 done(TabsOrientation, a);
1057 /*ARGSUSED*/
1058 #if NeedFunctionPrototypes
1059 static Boolean cvtTabsOrientationToString(Display * display,XrmValuePtr args,Cardinal * num_args,XrmValuePtr from,XrmValuePtr to,XtPointer * converter_data)
1060 #else
1061 static Boolean cvtTabsOrientationToString(display,args,num_args,from,to,converter_data)Display * display;XrmValuePtr args;Cardinal * num_args;XrmValuePtr from;XrmValuePtr to;XtPointer * converter_data;
1062 #endif
1064 TabsOrientation *a = (TabsOrientation*) from->addr;
1066 if (*num_args != 0)
1067 XtAppErrorMsg
1068 (XtDisplayToApplicationContext(display),
1069 "cvtTabsOrientationToString", "wrongParameters", "XtToolkitError",
1070 "TabsOrientation to String conversion needs no arguments",
1071 (String*) NULL, (Cardinal*) NULL);
1072 switch (*a) {
1073 case XfwfUpTabs: done(String, "up");
1074 case XfwfDownTabs: done(String, "down");
1075 case XfwfLeftTabs: done(String, "left");
1076 case XfwfRightTabs: done(String, "right");
1078 XtAppErrorMsg
1079 (XtDisplayToApplicationContext(display),
1080 "cvtTabsOrientationToString", "illParameters", "XtToolkitError",
1081 "TabsOrientation to String conversion got illegal argument",
1082 (String*) NULL, (Cardinal*) NULL);
1083 return TRUE;
1086 static XtResource resources[] = {
1087 {XtNorientation,XtCOrientation,XtRTabsOrientation,sizeof(((XmTabsRec*)NULL)->xmTabs.orientation),XtOffsetOf(XmTabsRec,xmTabs.orientation),XtRImmediate,(XtPointer)XfwfUpTabs },
1088 {XtNlefttabs,XtCLefttabs,XtRInt,sizeof(((XmTabsRec*)NULL)->xmTabs.lefttabs),XtOffsetOf(XmTabsRec,xmTabs.lefttabs),XtRImmediate,(XtPointer)0 },
1089 {XtNrighttabs,XtCRighttabs,XtRInt,sizeof(((XmTabsRec*)NULL)->xmTabs.righttabs),XtOffsetOf(XmTabsRec,xmTabs.righttabs),XtRImmediate,(XtPointer)0 },
1090 {XtNlabels,XtCLabels,XtRStringArray,sizeof(((XmTabsRec*)NULL)->xmTabs.labels),XtOffsetOf(XmTabsRec,xmTabs.labels),XtRImmediate,(XtPointer)NULL },
1091 {XtNtabWidthPercentage,XtCTabWidthPercentage,XtRInt,sizeof(((XmTabsRec*)NULL)->xmTabs.tabWidthPercentage),XtOffsetOf(XmTabsRec,xmTabs.tabWidthPercentage),XtRImmediate,(XtPointer)50 },
1092 {XtNcornerwidth,XtCCornerwidth,XtRCardinal,sizeof(((XmTabsRec*)NULL)->xmTabs.cornerwidth),XtOffsetOf(XmTabsRec,xmTabs.cornerwidth),XtRImmediate,(XtPointer)3 },
1093 {XtNcornerheight,XtCCornerheight,XtRCardinal,sizeof(((XmTabsRec*)NULL)->xmTabs.cornerheight),XtOffsetOf(XmTabsRec,xmTabs.cornerheight),XtRImmediate,(XtPointer)3 },
1094 {XtNtextmargin,XtCTextmargin,XtRInt,sizeof(((XmTabsRec*)NULL)->xmTabs.textmargin),XtOffsetOf(XmTabsRec,xmTabs.textmargin),XtRImmediate,(XtPointer)3 },
1095 {XtNtabcolor,XtCTabcolor,XtRPixel,sizeof(((XmTabsRec*)NULL)->xmTabs.tabcolor),XtOffsetOf(XmTabsRec,xmTabs.tabcolor),XtRCallProc,(XtPointer)copy_bg },
1096 {XtNfont,XtCFont,XtRFontStruct,sizeof(((XmTabsRec*)NULL)->xmTabs.font),XtOffsetOf(XmTabsRec,xmTabs.font),XtRString,(XtPointer)XtDefaultFont },
1097 {XtNactivateCallback,XtCActivateCallback,XtRCallback,sizeof(((XmTabsRec*)NULL)->xmTabs.activateCallback),XtOffsetOf(XmTabsRec,xmTabs.activateCallback),XtRImmediate,(XtPointer)NULL },
1100 XmTabsClassRec xmTabsClassRec = {
1101 { /* core_class part */
1102 /* superclass */ (WidgetClass) &xmManagerClassRec,
1103 /* class_name */ "XmTabs",
1104 /* widget_size */ sizeof(XmTabsRec),
1105 /* class_initialize */ class_initialize,
1106 /* class_part_initialize*/ _resolve_inheritance,
1107 /* class_inited */ FALSE,
1108 /* initialize */ initialize,
1109 /* initialize_hook */ NULL,
1110 /* realize */ realize,
1111 /* actions */ actionsList,
1112 /* num_actions */ 1,
1113 /* resources */ resources,
1114 /* num_resources */ 11,
1115 /* xrm_class */ NULLQUARK,
1116 /* compres_motion */ True ,
1117 /* compress_exposure */ XtExposeCompressMultiple ,
1118 /* compress_enterleave */ True ,
1119 /* visible_interest */ False ,
1120 /* destroy */ destroy,
1121 /* resize */ resize,
1122 /* expose */ expose,
1123 /* set_values */ set_values,
1124 /* set_values_hook */ NULL,
1125 /* set_values_almost */ XtInheritSetValuesAlmost,
1126 /* get_values+hook */ NULL,
1127 /* accept_focus */ XtInheritAcceptFocus,
1128 /* version */ XtVersion,
1129 /* callback_private */ NULL,
1130 /* tm_table */ defaultTranslations,
1131 /* query_geometry */ XtInheritQueryGeometry,
1132 /* display_acceleator */ XtInheritDisplayAccelerator,
1133 /* extension */ NULL
1135 { /* composite_class part */
1136 XtInheritGeometryManager,
1137 XtInheritChangeManaged,
1138 XtInheritInsertChild,
1139 XtInheritDeleteChild,
1140 NULL
1142 { /* constraint_class part */
1143 /* constraint_resources */ NULL,
1144 /* num_constraint_resources */ 0,
1145 /* constraint_size */ sizeof(XmTabsConstraintRec),
1146 /* constraint_initialize */ NULL,
1147 /* constraint_destroy */ NULL,
1148 /* constraint_set_values */ NULL,
1149 /* constraint_extension */ NULL
1151 { /* XmManager class part */
1152 #define manager_extension extension
1153 /* translations */ XtInheritTranslations ,
1154 /* syn_resources */ NULL ,
1155 /* num_syn_resources */ 0 ,
1156 /* syn_constraint_resources */ NULL ,
1157 /* num_syn_constraint_resources */ 0 ,
1158 /* parent_process */ XmInheritParentProcess,
1159 /* manager_extension */ NULL ,
1161 { /* XmTabs_class part */
1162 border_highlight,
1163 border_unhighlight,
1166 WidgetClass xmTabsWidgetClass = (WidgetClass) &xmTabsClassRec;
1167 /*ARGSUSED*/
1168 static void activate(Widget self, XEvent *event, String *params, Cardinal *num_params)
1170 int x0, x1, dummy, i, x, y;
1171 XPoint poly[12];
1173 switch (((XmTabsWidget)self)->xmTabs.orientation) {
1174 case XfwfUpTabs:
1175 case XfwfDownTabs:
1176 x = event->xbutton.x;
1177 comp_hor_tab_shape(self, ((XmTabsWidget)self)->xmTabs.lefttabs, poly, &x0, &x1, &dummy);
1178 if (x0 <= x && x < x1) {
1179 XtCallCallbackList(self, ((XmTabsWidget)self)->xmTabs.activateCallback, (XtPointer) 0);
1180 return;
1182 for (i = -1; i >= -((XmTabsWidget)self)->xmTabs.lefttabs; i--) {
1183 comp_hor_tab_shape(self, i + ((XmTabsWidget)self)->xmTabs.lefttabs, poly, &x0, &x1, &dummy);
1184 if (x0 <= x && x < x1) {
1185 XtCallCallbackList(self, ((XmTabsWidget)self)->xmTabs.activateCallback, (XtPointer) i);
1186 return;
1189 for (i = 1; i <= ((XmTabsWidget)self)->xmTabs.righttabs; i++) {
1190 comp_hor_tab_shape(self, i + ((XmTabsWidget)self)->xmTabs.lefttabs, poly, &x0, &x1, &dummy);
1191 if (x0 <= x && x < x1) {
1192 XtCallCallbackList(self, ((XmTabsWidget)self)->xmTabs.activateCallback, (XtPointer) i);
1193 return;
1196 break;
1197 case XfwfLeftTabs:
1198 case XfwfRightTabs:
1199 y = event->xbutton.y;
1200 comp_ver_tab_shape(self, ((XmTabsWidget)self)->xmTabs.lefttabs, poly, &x0, &x1, &dummy);
1201 if (x0 <= y && y < x1) {
1202 XtCallCallbackList(self, ((XmTabsWidget)self)->xmTabs.activateCallback, (XtPointer) 0);
1203 return;
1205 for (i = -1; i >= -((XmTabsWidget)self)->xmTabs.lefttabs; i--) {
1206 comp_ver_tab_shape(self, i + ((XmTabsWidget)self)->xmTabs.lefttabs, poly, &x0, &x1, &dummy);
1207 if (x0 <= y && y < x1) {
1208 XtCallCallbackList(self, ((XmTabsWidget)self)->xmTabs.activateCallback, (XtPointer) i);
1209 return;
1212 for (i = 1; i <= ((XmTabsWidget)self)->xmTabs.righttabs; i++) {
1213 comp_ver_tab_shape(self, i + ((XmTabsWidget)self)->xmTabs.lefttabs, poly, &x0, &x1, &dummy);
1214 if (x0 <= y && y < x1) {
1215 XtCallCallbackList(self, ((XmTabsWidget)self)->xmTabs.activateCallback, (XtPointer) i);
1216 return;
1219 break;
1223 static void _resolve_inheritance(WidgetClass class)
1225 XmTabsWidgetClass c = (XmTabsWidgetClass) class;
1226 XmTabsWidgetClass super;
1227 static CompositeClassExtensionRec extension_rec = {
1228 NULL, NULLQUARK, XtCompositeExtensionVersion,
1229 sizeof(CompositeClassExtensionRec), True};
1230 CompositeClassExtensionRec *ext;
1231 ext = (XtPointer)XtMalloc(sizeof(*ext));
1232 *ext = extension_rec;
1233 ext->next_extension = c->composite_class.extension;
1234 c->composite_class.extension = ext;
1235 if (class == xmTabsWidgetClass) return;
1236 super = (XmTabsWidgetClass)class->core_class.superclass;
1237 if (c->xmTabs_class.border_highlight == XtInherit_border_highlight)
1238 c->xmTabs_class.border_highlight = super->xmTabs_class.border_highlight;
1239 if (c->xmTabs_class.border_unhighlight == XtInherit_border_unhighlight)
1240 c->xmTabs_class.border_unhighlight = super->xmTabs_class.border_unhighlight;
1242 /*ARGSUSED*/
1243 #if NeedFunctionPrototypes
1244 static void class_initialize(void)
1245 #else
1246 static void class_initialize(void)
1247 #endif
1249 XtSetTypeConverter(XtRString, "StringArray",
1250 cvtStringToStringArray,
1251 NULL, 0, XtCacheNone, NULL);
1252 XtSetTypeConverter(XtRString, "TabsOrientation",
1253 cvtStringToTabsOrientation,
1254 NULL, 0, XtCacheNone, NULL);
1255 XtSetTypeConverter("TabsOrientation", XtRString,
1256 cvtTabsOrientationToString,
1257 NULL, 0, XtCacheNone, NULL);
1259 /*ARGSUSED*/
1260 #if NeedFunctionPrototypes
1261 static void initialize(Widget request,Widget self,ArgList args,Cardinal * num_args)
1262 #else
1263 static void initialize(request,self,args,num_args)Widget request;Widget self;ArgList args;Cardinal * num_args;
1264 #endif
1266 String *h;
1267 int i;
1269 ((XmTabsWidget)self)->xmManager.traversal_on = FALSE;
1270 ((XmTabsWidget)self)->xmTabs.topgc = NULL;
1271 create_topgc(self);
1272 ((XmTabsWidget)self)->xmTabs.bottomgc = NULL;
1273 create_bottomgc(self);
1274 ((XmTabsWidget)self)->xmTabs.textgc = NULL;
1275 create_textgc(self);
1276 ((XmTabsWidget)self)->xmTabs.fillgc = NULL;
1277 create_fillgc(self);
1278 ((XmTabsWidget)self)->xmTabs.backgc = NULL;
1279 create_backgc(self);
1280 if (((XmTabsWidget)self)->xmTabs.labels) {
1281 h = (String*) XtMalloc((((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs + 1) * sizeof(*h));
1282 for (i = ((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs; i >= 0; i--)
1283 h[i] = XtNewString(((XmTabsWidget)self)->xmTabs.labels[i]);
1284 ((XmTabsWidget)self)->xmTabs.labels = h;
1286 if (((XmTabsWidget)self)->xmTabs.tabWidthPercentage < 0 || ((XmTabsWidget)self)->xmTabs.tabWidthPercentage > 100) {
1287 XtAppWarning(XtWidgetToApplicationContext(self),
1288 "tabWidthPercentage out of range; reset to 50");
1289 ((XmTabsWidget)self)->xmTabs.tabWidthPercentage = 50;
1291 ((XmTabsWidget)self)->xmTabs.offsets = NULL;
1292 ((XmTabsWidget)self)->xmTabs.tabwidths = NULL;
1293 compute_tabsizes(self);
1295 /*ARGSUSED*/
1296 #if NeedFunctionPrototypes
1297 static Boolean set_values(Widget old,Widget request,Widget self,ArgList args,Cardinal * num_args)
1298 #else
1299 static Boolean set_values(old,request,self,args,num_args)Widget old;Widget request;Widget self;ArgList args;Cardinal * num_args;
1300 #endif
1302 Bool redraw = FALSE, resize_labels = FALSE;
1303 String *h;
1304 int i;
1306 if (((XmTabsWidget)self)->core.background_pixel != ((XmTabsWidget)old)->core.background_pixel
1307 || ((XmTabsWidget)self)->core.background_pixmap != ((XmTabsWidget)old)->core.background_pixmap
1308 || ((XmTabsWidget)self)->xmManager.shadow_thickness != ((XmTabsWidget)old)->xmManager.shadow_thickness) {
1309 create_topgc(self);
1310 create_bottomgc(self);
1311 create_backgc(self);
1313 if (((XmTabsWidget)self)->xmManager.foreground != ((XmTabsWidget)old)->xmManager.foreground || ((XmTabsWidget)self)->xmTabs.font != ((XmTabsWidget)old)->xmTabs.font) {
1314 create_textgc(self);
1315 redraw = TRUE;
1317 if (((XmTabsWidget)self)->xmTabs.tabcolor != ((XmTabsWidget)old)->xmTabs.tabcolor) {
1318 create_fillgc(self);
1319 redraw = TRUE;
1321 if ((((XmTabsWidget)self)->xmTabs.textmargin != ((XmTabsWidget)old)->xmTabs.textmargin && ((XmTabsWidget)self)->xmTabs.tabWidthPercentage == 0)
1322 || ((XmTabsWidget)self)->xmTabs.cornerwidth != ((XmTabsWidget)old)->xmTabs.cornerwidth
1323 || ((XmTabsWidget)self)->xmTabs.cornerheight != ((XmTabsWidget)old)->xmTabs.cornerheight) {
1324 resize_labels = TRUE;
1326 if (((XmTabsWidget)self)->xmTabs.labels != ((XmTabsWidget)old)->xmTabs.labels) {
1327 if (((XmTabsWidget)self)->xmTabs.labels) {
1328 h = (String*) XtMalloc((((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs + 1) * sizeof(*h));
1329 for (i = ((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs; i >= 0; i--)
1330 h[i] = XtNewString(((XmTabsWidget)self)->xmTabs.labels[i]);
1331 ((XmTabsWidget)self)->xmTabs.labels = h;
1333 if (((XmTabsWidget)old)->xmTabs.labels) {
1334 for (i = ((XmTabsWidget)old)->xmTabs.lefttabs + ((XmTabsWidget)old)->xmTabs.righttabs; i >= 0; i--)
1335 XtFree(((XmTabsWidget)old)->xmTabs.labels[i]);
1336 XtFree((XtPointer) ((XmTabsWidget)old)->xmTabs.labels);
1338 resize_labels = TRUE;
1340 if (((XmTabsWidget)self)->xmTabs.tabWidthPercentage < 0 || ((XmTabsWidget)self)->xmTabs.tabWidthPercentage > 100) {
1341 XtAppWarning(XtWidgetToApplicationContext(self),
1342 "tabWidthPercentage out of range; reset to 50");
1343 ((XmTabsWidget)self)->xmTabs.tabWidthPercentage = 50;
1345 if (((XmTabsWidget)old)->xmTabs.tabWidthPercentage != ((XmTabsWidget)self)->xmTabs.tabWidthPercentage)
1346 resize_labels = TRUE;
1347 if (((XmTabsWidget)self)->xmTabs.lefttabs != ((XmTabsWidget)old)->xmTabs.lefttabs || ((XmTabsWidget)self)->xmTabs.righttabs != ((XmTabsWidget)old)->xmTabs.righttabs)
1348 redraw = TRUE;
1349 if (resize_labels) {
1350 compute_tabsizes(self);
1351 redraw = TRUE;
1353 return redraw;
1355 /*ARGSUSED*/
1356 #if NeedFunctionPrototypes
1357 static void realize(Widget self,XtValueMask * mask,XSetWindowAttributes * attributes)
1358 #else
1359 static void realize(self,mask,attributes)Widget self;XtValueMask * mask;XSetWindowAttributes * attributes;
1360 #endif
1362 *mask |= CWBitGravity;
1363 attributes->bit_gravity = ForgetGravity;
1364 xmManagerClassRec.core_class.realize(self, mask, attributes);
1365 set_shape(self);
1367 /*ARGSUSED*/
1368 #if NeedFunctionPrototypes
1369 static void resize(Widget self)
1370 #else
1371 static void resize(self)Widget self;
1372 #endif
1374 if (XtIsRealized(self))
1375 XClearArea(XtDisplay(self), XtWindow(self), 0, 0, 0, 0, True);
1376 compute_tabsizes(self);
1377 set_shape(self);
1378 if ( xmManagerClassRec.core_class.resize ) xmManagerClassRec.core_class.resize(self);
1380 /*ARGSUSED*/
1381 #if NeedFunctionPrototypes
1382 static void expose(Widget self,XEvent * event,Region region)
1383 #else
1384 static void expose(self,event,region)Widget self;XEvent * event;Region region;
1385 #endif
1387 int i;
1389 if (! XtIsRealized(self)) return;
1391 switch (((XmTabsWidget)self)->xmTabs.orientation) {
1392 case XfwfUpTabs:
1393 case XfwfDownTabs:
1394 for (i = 0; i < ((XmTabsWidget)self)->xmTabs.lefttabs; i++)
1395 draw_hor_tab(self, region, i);
1396 for (i = ((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs; i > ((XmTabsWidget)self)->xmTabs.lefttabs; i--)
1397 draw_hor_tab(self, region, i);
1398 draw_hor_tab(self, region, ((XmTabsWidget)self)->xmTabs.lefttabs);
1399 break;
1400 case XfwfLeftTabs:
1401 case XfwfRightTabs:
1402 for (i = 0; i < ((XmTabsWidget)self)->xmTabs.lefttabs; i++)
1403 draw_ver_tab(self, region, i);
1404 for (i = ((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs; i > ((XmTabsWidget)self)->xmTabs.lefttabs; i--)
1405 draw_ver_tab(self, region, i);
1406 draw_ver_tab(self, region, ((XmTabsWidget)self)->xmTabs.lefttabs);
1407 break;
1409 /* Focus highlight? */
1411 /*ARGSUSED*/
1412 #if NeedFunctionPrototypes
1413 static void border_highlight(void)
1414 #else
1415 static void border_highlight(void)
1416 #endif
1419 /*ARGSUSED*/
1420 #if NeedFunctionPrototypes
1421 static void border_unhighlight(void)
1422 #else
1423 static void border_unhighlight(void)
1424 #endif
1427 /*ARGSUSED*/
1428 #if NeedFunctionPrototypes
1429 static void destroy(Widget self)
1430 #else
1431 static void destroy(self)Widget self;
1432 #endif
1434 int i;
1436 if (((XmTabsWidget)self)->xmTabs.labels) {
1437 for (i = ((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs; i >= 0; i--)
1438 XtFree(((XmTabsWidget)self)->xmTabs.labels[i]);
1439 XtFree((XtPointer) ((XmTabsWidget)self)->xmTabs.labels);
1441 if (((XmTabsWidget)self)->xmTabs.offsets)
1442 XtFree((XtPointer) ((XmTabsWidget)self)->xmTabs.offsets);
1443 if (((XmTabsWidget)self)->xmTabs.tabwidths)
1444 XtFree((XtPointer) ((XmTabsWidget)self)->xmTabs.tabwidths);
1448 /* ***********************************************************************
1449 * Routines for drawing rotated text
1450 * ***********************************************************************
1453 /* xvertext 5.0, Copyright (c) 1993 Alan Richardson (mppa3@uk.ac.sussex.syma)
1455 * Permission to use, copy, modify, and distribute this software and its
1456 * documentation for any purpose and without fee is hereby granted, provided
1457 * that the above copyright notice appear in all copies and that both the
1458 * copyright notice and this permission notice appear in supporting
1459 * documentation. All work developed as a consequence of the use of
1460 * this program should duly acknowledge such use. No representations are
1461 * made about the suitability of this software for any purpose. It is
1462 * provided "as is" without express or implied warranty.
1464 * 8 Jun '95: [Bert Bos] added GCClipXOrigin|GCClipYOrigin|GCClipMask
1465 * when calling XCopyGC()
1468 /* ********************************************************************** */
1471 /* BETTER: xvertext now does rotation at any angle!!
1473 * BEWARE: function arguments have CHANGED since version 2.0!!
1476 /* ********************************************************************** */
1480 /* ---------------------------------------------------------------------- */
1483 /* Make sure cache size is set */
1485 #ifndef CACHE_SIZE_LIMIT
1486 #define CACHE_SIZE_LIMIT 0
1487 #endif /*CACHE_SIZE_LIMIT */
1489 /* Make sure a cache method is specified */
1491 #ifndef CACHE_XIMAGES
1492 #ifndef CACHE_BITMAPS
1493 #define CACHE_BITMAPS
1494 #endif /*CACHE_BITMAPS*/
1495 #endif /*CACHE_XIMAGES*/
1498 /* ---------------------------------------------------------------------- */
1501 /* Debugging macros */
1503 #ifdef DEBUG
1504 static int debug=1;
1505 #else
1506 static int debug=0;
1507 #endif /*DEBUG*/
1509 #define DEBUG_PRINT1(a) if (debug) printf (a)
1510 #define DEBUG_PRINT2(a, b) if (debug) printf (a, b)
1511 #define DEBUG_PRINT3(a, b, c) if (debug) printf (a, b, c)
1512 #define DEBUG_PRINT4(a, b, c, d) if (debug) printf (a, b, c, d)
1513 #define DEBUG_PRINT5(a, b, c, d, e) if (debug) printf (a, b, c, d, e)
1516 /* ---------------------------------------------------------------------- */
1519 #ifndef M_PI
1520 #define M_PI 3.14159265358979323846
1521 #endif
1524 /* ---------------------------------------------------------------------- */
1527 /* A structure holding everything needed for a rotated string */
1529 typedef struct rotated_text_item_template {
1530 Pixmap bitmap;
1531 XImage *ximage;
1533 char *text;
1534 char *font_name;
1535 Font fid;
1536 float angle;
1537 int align;
1538 float magnify;
1540 int cols_in;
1541 int rows_in;
1542 int cols_out;
1543 int rows_out;
1545 int nl;
1546 int max_width;
1547 float *corners_x;
1548 float *corners_y;
1550 long int size;
1551 int cached;
1553 struct rotated_text_item_template *next;
1554 } RotatedTextItem;
1556 RotatedTextItem *first_text_item=NULL;
1559 /* ---------------------------------------------------------------------- */
1562 /* A structure holding current magnification and bounding box padding */
1564 static struct style_template {
1565 float magnify;
1566 int bbx_pad;
1567 } style={
1573 /* ---------------------------------------------------------------------- */
1576 static char *my_strdup(char *str);
1577 static char *my_strtok(char *str1, char *str2);
1579 static float XRotVersion(char *str, int n);
1580 static void XRotSetMagnification(float m);
1581 static void XRotSetBoundingBoxPad(int p);
1582 static int XRotDrawString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *str);
1583 static int XRotDrawImageString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *str);
1584 static int XRotDrawAlignedString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text, int align);
1585 static int XRotDrawAlignedImageString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text, int align);
1586 static XPoint *XRotTextExtents(Display *dpy, XFontStruct *font, float angle, int x, int y, char *text, int align);
1588 static XImage *MakeXImage(Display *dpy, int w, int h);
1589 static int XRotPaintAlignedString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text, int align, int bg);
1590 static int XRotDrawHorizontalString(Display *dpy, XFontStruct *font, Drawable drawable, GC gc, int x, int y, char *text, int align, int bg);
1591 static RotatedTextItem *XRotRetrieveFromCache(Display *dpy, XFontStruct *font, float angle, char *text, int align);
1592 static RotatedTextItem *XRotCreateTextItem(Display *dpy, XFontStruct *font, float angle, char *text, int align);
1593 static void XRotAddToLinkedList(Display *dpy, RotatedTextItem *item);
1594 static void XRotFreeTextItem(Display *dpy, RotatedTextItem *item);
1595 static XImage *XRotMagnifyImage(Display *dpy, XImage *ximage);
1598 /* ---------------------------------------------------------------------- */
1601 /**************************************************************************/
1602 /* Routine to mimic `strdup()' (some machines don't have it) */
1603 /**************************************************************************/
1605 static char *my_strdup(char *str)
1607 char *s;
1609 if(str==NULL)
1610 return NULL;
1612 s=(char *)malloc((unsigned)(strlen(str)+1));
1613 if(s!=NULL)
1614 strcpy(s, str);
1616 return s;
1620 /* ---------------------------------------------------------------------- */
1623 /**************************************************************************/
1624 /* Routine to replace `strtok' : this one returns a zero length string if */
1625 /* it encounters two consecutive delimiters */
1626 /**************************************************************************/
1628 static char *my_strtok(char *str1, char *str2)
1630 char *ret;
1631 int i, j, stop;
1632 static int start, len;
1633 static char *stext;
1635 if(str2==NULL)
1636 return NULL;
1638 /* initialise if str1 not NULL */
1639 if(str1!=NULL) {
1640 start=0;
1641 stext=str1;
1642 len=strlen(str1);
1645 /* run out of tokens ? */
1646 if(start>=len)
1647 return NULL;
1649 /* loop through characters */
1650 for(i=start; i<len; i++) {
1651 /* loop through delimiters */
1652 stop=0;
1653 for(j=0; j<strlen(str2); j++)
1654 if(stext[i]==str2[j])
1655 stop=1;
1657 if(stop)
1658 break;
1661 stext[i]='\0';
1663 ret=stext+start;
1665 start=i+1;
1667 return ret;
1671 /* ---------------------------------------------------------------------- */
1674 /**************************************************************************/
1675 /* Return version/copyright information */
1676 /**************************************************************************/
1677 static
1678 float XRotVersion(char *str, int n)
1680 if(str!=NULL)
1681 strncpy(str, XV_COPYRIGHT, n);
1682 return XV_VERSION;
1686 /* ---------------------------------------------------------------------- */
1689 /**************************************************************************/
1690 /* Set the font magnification factor for all subsequent operations */
1691 /**************************************************************************/
1692 static
1693 void XRotSetMagnification(float m)
1695 if(m>0.)
1696 style.magnify=m;
1700 /* ---------------------------------------------------------------------- */
1703 /**************************************************************************/
1704 /* Set the padding used when calculating bounding boxes */
1705 /**************************************************************************/
1706 static
1707 void XRotSetBoundingBoxPad(int p)
1709 if(p>=0)
1710 style.bbx_pad=p;
1714 /* ---------------------------------------------------------------------- */
1717 /**************************************************************************/
1718 /* Create an XImage structure and allocate memory for it */
1719 /**************************************************************************/
1721 static XImage *MakeXImage(Display *dpy, int w, int h)
1723 XImage *I;
1724 char *data;
1726 /* reserve memory for image */
1727 data=(char *)calloc((unsigned)(((w-1)/8+1)*h), 1);
1728 if(data==NULL)
1729 return NULL;
1731 /* create the XImage */
1732 I=XCreateImage(dpy, DefaultVisual(dpy, DefaultScreen(dpy)), 1, XYBitmap,
1733 0, data, w, h, 8, 0);
1734 if(I==NULL)
1735 return NULL;
1737 I->byte_order=I->bitmap_bit_order=MSBFirst;
1738 return I;
1742 /* ---------------------------------------------------------------------- */
1745 /**************************************************************************/
1746 /* A front end to XRotPaintAlignedString: */
1747 /* -no alignment, no background */
1748 /**************************************************************************/
1749 static
1750 int XRotDrawString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *str)
1752 return (XRotPaintAlignedString(dpy, font, angle, drawable, gc,
1753 x, y, str, NONE, 0));
1757 /* ---------------------------------------------------------------------- */
1760 /**************************************************************************/
1761 /* A front end to XRotPaintAlignedString: */
1762 /* -no alignment, paints background */
1763 /**************************************************************************/
1764 static
1765 int XRotDrawImageString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *str)
1767 return(XRotPaintAlignedString(dpy, font, angle, drawable, gc,
1768 x, y, str, NONE, 1));
1772 /* ---------------------------------------------------------------------- */
1775 /**************************************************************************/
1776 /* A front end to XRotPaintAlignedString: */
1777 /* -does alignment, no background */
1778 /**************************************************************************/
1779 static
1780 int XRotDrawAlignedString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text, int align)
1782 return(XRotPaintAlignedString(dpy, font, angle, drawable, gc,
1783 x, y, text, align, 0));
1787 /* ---------------------------------------------------------------------- */
1790 /**************************************************************************/
1791 /* A front end to XRotPaintAlignedString: */
1792 /* -does alignment, paints background */
1793 /**************************************************************************/
1794 static
1795 int XRotDrawAlignedImageString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text, int align)
1797 return(XRotPaintAlignedString(dpy, font, angle, drawable, gc,
1798 x, y, text, align, 1));
1802 /* ---------------------------------------------------------------------- */
1805 /**************************************************************************/
1806 /* Aligns and paints a rotated string */
1807 /**************************************************************************/
1809 static int XRotPaintAlignedString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text, int align, int bg)
1811 int i;
1812 GC my_gc;
1813 int xp, yp;
1814 float hot_x, hot_y;
1815 float hot_xp, hot_yp;
1816 float sin_angle, cos_angle;
1817 RotatedTextItem *item;
1818 Pixmap bitmap_to_paint;
1820 /* return early for NULL/empty strings */
1821 if(text==NULL)
1822 return 0;
1824 if(strlen(text)==0)
1825 return 0;
1827 /* manipulate angle to 0<=angle<360 degrees */
1828 while(angle<0)
1829 angle+=360;
1831 while(angle>=360)
1832 angle-=360;
1834 angle*=M_PI/180;
1836 /* horizontal text made easy */
1837 if(angle==0. && style.magnify==1.)
1838 return(XRotDrawHorizontalString(dpy, font, drawable, gc, x, y,
1839 text, align, bg));
1841 /* get a rotated bitmap */
1842 item=XRotRetrieveFromCache(dpy, font, angle, text, align);
1843 if(item==NULL)
1844 return NULL;
1846 /* this gc has similar properties to the user's gc */
1847 my_gc=XCreateGC(dpy, drawable, NULL, 0);
1848 XCopyGC(dpy, gc, GCForeground|GCBackground|GCFunction|GCPlaneMask
1849 |GCClipXOrigin|GCClipYOrigin|GCClipMask, my_gc);
1851 /* alignment : which point (hot_x, hot_y) relative to bitmap centre
1852 coincides with user's specified point? */
1854 /* y position */
1855 if(align==TLEFT || align==TCENTRE || align==TRIGHT)
1856 hot_y=(float)item->rows_in/2*style.magnify;
1857 else if(align==MLEFT || align==MCENTRE || align==MRIGHT)
1858 hot_y=0;
1859 else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
1860 hot_y = -(float)item->rows_in/2*style.magnify;
1861 else
1862 hot_y = -((float)item->rows_in/2-(float)font->descent)*style.magnify;
1864 /* x position */
1865 if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
1866 hot_x = -(float)item->max_width/2*style.magnify;
1867 else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
1868 hot_x=0;
1869 else
1870 hot_x=(float)item->max_width/2*style.magnify;
1872 /* pre-calculate sin and cos */
1873 sin_angle=sin(angle);
1874 cos_angle=cos(angle);
1876 /* rotate hot_x and hot_y around bitmap centre */
1877 hot_xp= hot_x*cos_angle - hot_y*sin_angle;
1878 hot_yp= hot_x*sin_angle + hot_y*cos_angle;
1880 /* text background will be drawn using XFillPolygon */
1881 if(bg) {
1882 GC depth_one_gc;
1883 XPoint *xpoints;
1884 Pixmap empty_stipple;
1886 /* reserve space for XPoints */
1887 xpoints=(XPoint *)malloc((unsigned)(4*item->nl*sizeof(XPoint)));
1888 if(!xpoints)
1889 return 1;
1891 /* rotate corner positions */
1892 for(i=0; i<4*item->nl; i++) {
1893 xpoints[i].x=(float)x + ( (item->corners_x[i]-hot_x)*cos_angle +
1894 (item->corners_y[i]+hot_y)*sin_angle);
1895 xpoints[i].y=(float)y + (-(item->corners_x[i]-hot_x)*sin_angle +
1896 (item->corners_y[i]+hot_y)*cos_angle);
1899 /* we want to swap foreground and background colors here;
1900 XGetGCValues() is only available in R4+ */
1902 empty_stipple=XCreatePixmap(dpy, drawable, 1, 1, 1);
1904 depth_one_gc=XCreateGC(dpy, empty_stipple, NULL, 0);
1905 XSetForeground(dpy, depth_one_gc, 0);
1906 XFillRectangle(dpy, empty_stipple, depth_one_gc, 0, 0, 2, 2);
1908 XSetStipple(dpy, my_gc, empty_stipple);
1909 XSetFillStyle(dpy, my_gc, FillOpaqueStippled);
1911 XFillPolygon(dpy, drawable, my_gc, xpoints, 4*item->nl, Nonconvex,
1912 CoordModeOrigin);
1914 /* free our resources */
1915 free((char *)xpoints);
1916 XFreeGC(dpy, depth_one_gc);
1917 XFreePixmap(dpy, empty_stipple);
1920 /* where should top left corner of bitmap go ? */
1921 xp=(float)x-((float)item->cols_out/2 +hot_xp);
1922 yp=(float)y-((float)item->rows_out/2 -hot_yp);
1924 /* by default we draw the rotated bitmap, solid */
1925 bitmap_to_paint=item->bitmap;
1927 /* handle user stippling */
1928 #ifndef X11R3
1930 GC depth_one_gc;
1931 XGCValues values;
1932 Pixmap new_bitmap, inverse;
1934 /* try and get some GC properties */
1935 if(XGetGCValues(dpy, gc,
1936 GCStipple|GCFillStyle|GCForeground|GCBackground|
1937 GCTileStipXOrigin|GCTileStipYOrigin,
1938 &values)) {
1940 /* only do this if stippling requested */
1941 if((values.fill_style==FillStippled ||
1942 values.fill_style==FillOpaqueStippled) && !bg) {
1944 /* opaque stipple: draw rotated text in background colour */
1945 if(values.fill_style==FillOpaqueStippled) {
1946 XSetForeground(dpy, my_gc, values.background);
1947 XSetFillStyle(dpy, my_gc, FillStippled);
1948 XSetStipple(dpy, my_gc, item->bitmap);
1949 XSetTSOrigin(dpy, my_gc, xp, yp);
1950 XFillRectangle(dpy, drawable, my_gc, xp, yp,
1951 item->cols_out, item->rows_out);
1952 XSetForeground(dpy, my_gc, values.foreground);
1955 /* this will merge the rotated text and the user's stipple */
1956 new_bitmap=XCreatePixmap(dpy, drawable,
1957 item->cols_out, item->rows_out, 1);
1959 /* create a GC */
1960 depth_one_gc=XCreateGC(dpy, new_bitmap, NULL, 0);
1961 XSetForeground(dpy, depth_one_gc, 1);
1962 XSetBackground(dpy, depth_one_gc, 0);
1964 /* set the relative stipple origin */
1965 XSetTSOrigin(dpy, depth_one_gc,
1966 values.ts_x_origin-xp, values.ts_y_origin-yp);
1968 /* fill the whole bitmap with the user's stipple */
1969 XSetStipple(dpy, depth_one_gc, values.stipple);
1970 XSetFillStyle(dpy, depth_one_gc, FillOpaqueStippled);
1971 XFillRectangle(dpy, new_bitmap, depth_one_gc,
1972 0, 0, item->cols_out, item->rows_out);
1974 /* set stipple origin back to normal */
1975 XSetTSOrigin(dpy, depth_one_gc, 0, 0);
1977 /* this will contain an inverse copy of the rotated text */
1978 inverse=XCreatePixmap(dpy, drawable,
1979 item->cols_out, item->rows_out, 1);
1981 /* invert text */
1982 XSetFillStyle(dpy, depth_one_gc, FillSolid);
1983 XSetFunction(dpy, depth_one_gc, GXcopyInverted);
1984 XCopyArea(dpy, item->bitmap, inverse, depth_one_gc,
1985 0, 0, item->cols_out, item->rows_out, 0, 0);
1987 /* now delete user's stipple everywhere EXCEPT on text */
1988 XSetForeground(dpy, depth_one_gc, 0);
1989 XSetBackground(dpy, depth_one_gc, 1);
1990 XSetStipple(dpy, depth_one_gc, inverse);
1991 XSetFillStyle(dpy, depth_one_gc, FillStippled);
1992 XSetFunction(dpy, depth_one_gc, GXcopy);
1993 XFillRectangle(dpy, new_bitmap, depth_one_gc,
1994 0, 0, item->cols_out, item->rows_out);
1996 /* free resources */
1997 XFreePixmap(dpy, inverse);
1998 XFreeGC(dpy, depth_one_gc);
2000 /* this is the new bitmap */
2001 bitmap_to_paint=new_bitmap;
2005 #endif /*X11R3*/
2007 /* paint text using stipple technique */
2008 XSetFillStyle(dpy, my_gc, FillStippled);
2009 XSetStipple(dpy, my_gc, bitmap_to_paint);
2010 XSetTSOrigin(dpy, my_gc, xp, yp);
2011 XFillRectangle(dpy, drawable, my_gc, xp, yp,
2012 item->cols_out, item->rows_out);
2014 /* free our resources */
2015 XFreeGC(dpy, my_gc);
2017 /* stippled bitmap no longer needed */
2018 if(bitmap_to_paint!=item->bitmap)
2019 XFreePixmap(dpy, bitmap_to_paint);
2021 #ifdef CACHE_XIMAGES
2022 XFreePixmap(dpy, item->bitmap);
2023 #endif /*CACHE_XIMAGES*/
2025 /* if item isn't cached, destroy it completely */
2026 if(!item->cached)
2027 XRotFreeTextItem(dpy,item);
2029 /* we got to the end OK! */
2030 return 0;
2034 /* ---------------------------------------------------------------------- */
2037 /**************************************************************************/
2038 /* Draw a horizontal string in a quick fashion */
2039 /**************************************************************************/
2041 static int XRotDrawHorizontalString(Display *dpy, XFontStruct *font, Drawable drawable, GC gc, int x, int y, char *text, int align, int bg)
2043 GC my_gc;
2044 int nl=1, i;
2045 int height;
2046 int xp, yp;
2047 char *str1, *str2, *str3;
2048 char *str2_a="\0", *str2_b="\n\0";
2049 int dir, asc, desc;
2050 XCharStruct overall;
2052 DEBUG_PRINT1("**\nHorizontal text.\n");
2054 /* this gc has similar properties to the user's gc (including stipple) */
2055 my_gc=XCreateGC(dpy, drawable, NULL, 0);
2056 XCopyGC(dpy, gc,
2057 GCForeground|GCBackground|GCFunction|GCStipple|GCFillStyle|
2058 GCTileStipXOrigin|GCTileStipYOrigin|GCPlaneMask|
2059 GCClipXOrigin|GCClipYOrigin|GCClipMask, my_gc);
2060 XSetFont(dpy, my_gc, font->fid);
2062 /* count number of sections in string */
2063 if(align!=NONE)
2064 for(i=0; i<strlen(text)-1; i++)
2065 if(text[i]=='\n')
2066 nl++;
2068 /* ignore newline characters if not doing alignment */
2069 if(align==NONE)
2070 str2=str2_a;
2071 else
2072 str2=str2_b;
2074 /* overall font height */
2075 height=font->ascent+font->descent;
2077 /* y position */
2078 if(align==TLEFT || align==TCENTRE || align==TRIGHT)
2079 yp=y+font->ascent;
2080 else if(align==MLEFT || align==MCENTRE || align==MRIGHT)
2081 yp=y-nl*height/2+font->ascent;
2082 else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
2083 yp=y-nl*height+font->ascent;
2084 else
2085 yp=y;
2087 str1=my_strdup(text);
2088 if(str1==NULL)
2089 return 1;
2091 str3=my_strtok(str1, str2);
2093 /* loop through each section in the string */
2094 do {
2095 XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
2096 &overall);
2098 /* where to draw section in x ? */
2099 if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
2100 xp=x;
2101 else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
2102 xp=x-overall.rbearing/2;
2103 else
2104 xp=x-overall.rbearing;
2106 /* draw string onto bitmap */
2107 if(!bg)
2108 XDrawString(dpy, drawable, my_gc, xp, yp, str3, strlen(str3));
2109 else
2110 XDrawImageString(dpy, drawable, my_gc, xp, yp, str3, strlen(str3));
2112 /* move to next line */
2113 yp+=height;
2115 str3=my_strtok((char *)NULL, str2);
2117 while(str3!=NULL);
2119 free(str1);
2120 XFreeGC(dpy, my_gc);
2122 return 0;
2126 /* ---------------------------------------------------------------------- */
2129 /**************************************************************************/
2130 /* Query cache for a match with this font/text/angle/alignment */
2131 /* request, otherwise arrange for its creation */
2132 /**************************************************************************/
2134 static RotatedTextItem *XRotRetrieveFromCache(Display *dpy, XFontStruct *font, float angle, char *text, int align)
2136 Font fid;
2137 char *font_name=NULL;
2138 unsigned long name_value;
2139 RotatedTextItem *item=NULL;
2140 RotatedTextItem *i1=first_text_item;
2142 /* get font name, if it exists */
2143 if(XGetFontProperty(font, XA_FONT, &name_value)) {
2144 DEBUG_PRINT1("got font name OK\n");
2145 font_name=XGetAtomName(dpy, name_value);
2146 fid=0;
2148 #ifdef CACHE_FID
2149 /* otherwise rely (unreliably?) on font ID */
2150 else {
2151 DEBUG_PRINT1("can't get fontname, caching FID\n");
2152 font_name=NULL;
2153 fid=font->fid;
2155 #else
2156 /* not allowed to cache font ID's */
2157 else {
2158 DEBUG_PRINT1("can't get fontname, can't cache\n");
2159 font_name=NULL;
2160 fid=0;
2162 #endif /*CACHE_FID*/
2164 /* look for a match in cache */
2166 /* matching formula:
2167 identical text;
2168 identical fontname (if defined, font ID's if not);
2169 angles close enough (<0.00001 here, could be smaller);
2170 HORIZONTAL alignment matches, OR it's a one line string;
2171 magnifications the same */
2173 while(i1 && !item) {
2174 /* match everything EXCEPT fontname/ID */
2175 if(strcmp(text, i1->text)==0 &&
2176 fabs(angle-i1->angle)<0.00001 &&
2177 style.magnify==i1->magnify &&
2178 (i1->nl==1 ||
2179 ((align==0)?9:(align-1))%3==
2180 ((i1->align==0)?9:(i1->align-1))%3)) {
2182 /* now match fontname/ID */
2183 if(font_name!=NULL && i1->font_name!=NULL) {
2184 if(strcmp(font_name, i1->font_name)==0) {
2185 item=i1;
2186 DEBUG_PRINT1("Matched against font names\n");
2188 else
2189 i1=i1->next;
2191 #ifdef CACHE_FID
2192 else if(font_name==NULL && i1->font_name==NULL) {
2193 if(fid==i1->fid) {
2194 item=i1;
2195 DEBUG_PRINT1("Matched against FID's\n");
2197 else
2198 i1=i1->next;
2200 #endif /*CACHE_FID*/
2201 else
2202 i1=i1->next;
2204 else
2205 i1=i1->next;
2208 if(item)
2209 DEBUG_PRINT1("**\nFound target in cache.\n");
2210 if(!item)
2211 DEBUG_PRINT1("**\nNo match in cache.\n");
2213 /* no match */
2214 if(!item) {
2215 /* create new item */
2216 item=XRotCreateTextItem(dpy, font, angle, text, align);
2217 if(!item)
2218 return NULL;
2220 /* record what it shows */
2221 item->text=my_strdup(text);
2223 /* fontname or ID */
2224 if(font_name!=NULL) {
2225 item->font_name=my_strdup(font_name);
2226 item->fid=0;
2228 else {
2229 item->font_name=NULL;
2230 item->fid=fid;
2233 item->angle=angle;
2234 item->align=align;
2235 item->magnify=style.magnify;
2237 /* cache it */
2238 XRotAddToLinkedList(dpy, item);
2241 if(font_name)
2242 XFree(font_name);
2244 /* if XImage is cached, need to recreate the bitmap */
2246 #ifdef CACHE_XIMAGES
2248 GC depth_one_gc;
2250 /* create bitmap to hold rotated text */
2251 item->bitmap=XCreatePixmap(dpy, DefaultRootWindow(dpy),
2252 item->cols_out, item->rows_out, 1);
2254 /* depth one gc */
2255 depth_one_gc=XCreateGC(dpy, item->bitmap, NULL, 0);
2256 XSetBackground(dpy, depth_one_gc, 0);
2257 XSetForeground(dpy, depth_one_gc, 1);
2259 /* make the text bitmap from XImage */
2260 XPutImage(dpy, item->bitmap, depth_one_gc, item->ximage, 0, 0, 0, 0,
2261 item->cols_out, item->rows_out);
2263 XFreeGC(dpy, depth_one_gc);
2265 #endif /*CACHE_XIMAGES*/
2267 return item;
2271 /* ---------------------------------------------------------------------- */
2274 /**************************************************************************/
2275 /* Create a rotated text item */
2276 /**************************************************************************/
2278 static RotatedTextItem *XRotCreateTextItem(Display *dpy, XFontStruct *font, float angle, char *text, int align)
2280 RotatedTextItem *item=NULL;
2281 Pixmap canvas;
2282 GC font_gc;
2283 XImage *I_in;
2284 register int i, j;
2285 char *str1, *str2, *str3;
2286 char *str2_a="\0", *str2_b="\n\0";
2287 int height;
2288 int byte_w_in, byte_w_out;
2289 int xp, yp;
2290 float sin_angle, cos_angle;
2291 int it, jt;
2292 float di, dj;
2293 int ic=0;
2294 float xl, xr, xinc;
2295 int byte_out;
2296 int dir, asc, desc;
2297 XCharStruct overall;
2298 int old_cols_in=0, old_rows_in=0;
2300 /* allocate memory */
2301 item=(RotatedTextItem *)malloc((unsigned)sizeof(RotatedTextItem));
2302 if(!item)
2303 return NULL;
2305 /* count number of sections in string */
2306 item->nl=1;
2307 if(align!=NONE)
2308 for(i=0; i<strlen(text)-1; i++)
2309 if(text[i]=='\n')
2310 item->nl++;
2312 /* ignore newline characters if not doing alignment */
2313 if(align==NONE)
2314 str2=str2_a;
2315 else
2316 str2=str2_b;
2318 /* find width of longest section */
2319 str1=my_strdup(text);
2320 if(str1==NULL)
2321 return NULL;
2323 str3=my_strtok(str1, str2);
2325 XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
2326 &overall);
2328 item->max_width=overall.rbearing;
2330 /* loop through each section */
2331 do {
2332 str3=my_strtok((char *)NULL, str2);
2334 if(str3!=NULL) {
2335 XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
2336 &overall);
2338 if(overall.rbearing>item->max_width)
2339 item->max_width=overall.rbearing;
2342 while(str3!=NULL);
2344 free(str1);
2346 /* overall font height */
2347 height=font->ascent+font->descent;
2349 /* dimensions horizontal text will have */
2350 item->cols_in=item->max_width;
2351 item->rows_in=item->nl*height;
2353 /* bitmap for drawing on */
2354 canvas=XCreatePixmap(dpy, DefaultRootWindow(dpy),
2355 item->cols_in, item->rows_in, 1);
2357 /* create a GC for the bitmap */
2358 font_gc=XCreateGC(dpy, canvas, NULL, 0);
2359 XSetBackground(dpy, font_gc, 0);
2360 XSetFont(dpy, font_gc, font->fid);
2362 /* make sure the bitmap is blank */
2363 XSetForeground(dpy, font_gc, 0);
2364 XFillRectangle(dpy, canvas, font_gc, 0, 0,
2365 item->cols_in+1, item->rows_in+1);
2366 XSetForeground(dpy, font_gc, 1);
2368 /* pre-calculate sin and cos */
2369 sin_angle=sin(angle);
2370 cos_angle=cos(angle);
2372 /* text background will be drawn using XFillPolygon */
2373 item->corners_x=
2374 (float *)malloc((unsigned)(4*item->nl*sizeof(float)));
2375 if(!item->corners_x)
2376 return NULL;
2378 item->corners_y=
2379 (float *)malloc((unsigned)(4*item->nl*sizeof(float)));
2380 if(!item->corners_y)
2381 return NULL;
2383 /* draw text horizontally */
2385 /* start at top of bitmap */
2386 yp=font->ascent;
2388 str1=my_strdup(text);
2389 if(str1==NULL)
2390 return NULL;
2392 str3=my_strtok(str1, str2);
2394 /* loop through each section in the string */
2395 do {
2396 XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
2397 &overall);
2399 /* where to draw section in x ? */
2400 if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
2401 xp=0;
2402 else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
2403 xp=(item->max_width-overall.rbearing)/2;
2404 else
2405 xp=item->max_width-overall.rbearing;
2407 /* draw string onto bitmap */
2408 XDrawString(dpy, canvas, font_gc, xp, yp, str3, strlen(str3));
2410 /* keep a note of corner positions of this string */
2411 item->corners_x[ic]=((float)xp-(float)item->cols_in/2)*style.magnify;
2412 item->corners_y[ic]=((float)(yp-font->ascent)-(float)item->rows_in/2)
2413 *style.magnify;
2414 item->corners_x[ic+1]=item->corners_x[ic];
2415 item->corners_y[ic+1]=item->corners_y[ic]+(float)height*style.magnify;
2416 item->corners_x[item->nl*4-1-ic]=item->corners_x[ic]+
2417 (float)overall.rbearing*style.magnify;
2418 item->corners_y[item->nl*4-1-ic]=item->corners_y[ic];
2419 item->corners_x[item->nl*4-2-ic]=
2420 item->corners_x[item->nl*4-1-ic];
2421 item->corners_y[item->nl*4-2-ic]=item->corners_y[ic+1];
2423 ic+=2;
2425 /* move to next line */
2426 yp+=height;
2428 str3=my_strtok((char *)NULL, str2);
2430 while(str3!=NULL);
2432 free(str1);
2434 /* create image to hold horizontal text */
2435 I_in=MakeXImage(dpy, item->cols_in, item->rows_in);
2436 if(I_in==NULL)
2437 return NULL;
2439 /* extract horizontal text */
2440 XGetSubImage(dpy, canvas, 0, 0, item->cols_in, item->rows_in,
2441 1, XYPixmap, I_in, 0, 0);
2442 I_in->format=XYBitmap;
2444 /* magnify horizontal text */
2445 if(style.magnify!=1.) {
2446 I_in=XRotMagnifyImage(dpy, I_in);
2448 old_cols_in=item->cols_in;
2449 old_rows_in=item->rows_in;
2450 item->cols_in=(float)item->cols_in*style.magnify;
2451 item->rows_in=(float)item->rows_in*style.magnify;
2454 /* how big will rotated text be ? */
2455 item->cols_out=fabs((float)item->rows_in*sin_angle) +
2456 fabs((float)item->cols_in*cos_angle) +0.99999 +2;
2458 item->rows_out=fabs((float)item->rows_in*cos_angle) +
2459 fabs((float)item->cols_in*sin_angle) +0.99999 +2;
2461 if(item->cols_out%2==0)
2462 item->cols_out++;
2464 if(item->rows_out%2==0)
2465 item->rows_out++;
2467 /* create image to hold rotated text */
2468 item->ximage=MakeXImage(dpy, item->cols_out, item->rows_out);
2469 if(item->ximage==NULL)
2470 return NULL;
2472 byte_w_in=(item->cols_in-1)/8+1;
2473 byte_w_out=(item->cols_out-1)/8+1;
2475 /* we try to make this bit as fast as possible - which is why it looks
2476 a bit over-the-top */
2478 /* vertical distance from centre */
2479 dj=0.5-(float)item->rows_out/2;
2481 /* where abouts does text actually lie in rotated image? */
2482 if(angle==0 || angle==M_PI/2 ||
2483 angle==M_PI || angle==3*M_PI/2) {
2484 xl=0;
2485 xr=(float)item->cols_out;
2486 xinc=0;
2488 else if(angle<M_PI) {
2489 xl=(float)item->cols_out/2+
2490 (dj-(float)item->rows_in/(2*cos_angle))/
2491 tan(angle)-2;
2492 xr=(float)item->cols_out/2+
2493 (dj+(float)item->rows_in/(2*cos_angle))/
2494 tan(angle)+2;
2495 xinc=1./tan(angle);
2497 else {
2498 xl=(float)item->cols_out/2+
2499 (dj+(float)item->rows_in/(2*cos_angle))/
2500 tan(angle)-2;
2501 xr=(float)item->cols_out/2+
2502 (dj-(float)item->rows_in/(2*cos_angle))/
2503 tan(angle)+2;
2505 xinc=1./tan(angle);
2508 /* loop through all relevent bits in rotated image */
2509 for(j=0; j<item->rows_out; j++) {
2511 /* no point re-calculating these every pass */
2512 di=(float)((xl<0)?0:(int)xl)+0.5-(float)item->cols_out/2;
2513 byte_out=(item->rows_out-j-1)*byte_w_out;
2515 /* loop through meaningful columns */
2516 for(i=((xl<0)?0:(int)xl);
2517 i<((xr>=item->cols_out)?item->cols_out:(int)xr); i++) {
2519 /* rotate coordinates */
2520 it=(float)item->cols_in/2 + ( di*cos_angle + dj*sin_angle);
2521 jt=(float)item->rows_in/2 - (-di*sin_angle + dj*cos_angle);
2523 /* set pixel if required */
2524 if(it>=0 && it<item->cols_in && jt>=0 && jt<item->rows_in)
2525 if((I_in->data[jt*byte_w_in+it/8] & 128>>(it%8))>0)
2526 item->ximage->data[byte_out+i/8]|=128>>i%8;
2528 di+=1;
2530 dj+=1;
2531 xl+=xinc;
2532 xr+=xinc;
2534 XDestroyImage(I_in);
2536 if(style.magnify!=1.) {
2537 item->cols_in=old_cols_in;
2538 item->rows_in=old_rows_in;
2542 #ifdef CACHE_BITMAPS
2544 /* create a bitmap to hold rotated text */
2545 item->bitmap=XCreatePixmap(dpy, DefaultRootWindow(dpy),
2546 item->cols_out, item->rows_out, 1);
2548 /* make the text bitmap from XImage */
2549 XPutImage(dpy, item->bitmap, font_gc, item->ximage, 0, 0, 0, 0,
2550 item->cols_out, item->rows_out);
2552 XDestroyImage(item->ximage);
2554 #endif /*CACHE_BITMAPS*/
2556 XFreeGC(dpy, font_gc);
2557 XFreePixmap(dpy, canvas);
2559 return item;
2563 /* ---------------------------------------------------------------------- */
2566 /**************************************************************************/
2567 /* Adds a text item to the end of the cache, removing as many items */
2568 /* from the front as required to keep cache size below limit */
2569 /**************************************************************************/
2571 static void XRotAddToLinkedList(Display *dpy, RotatedTextItem *item)
2574 static long int current_size=0;
2575 static RotatedTextItem *last=NULL;
2576 RotatedTextItem *i1=first_text_item, *i2=NULL;
2578 #ifdef CACHE_BITMAPS
2580 /* I don't know how much memory a pixmap takes in the server -
2581 probably this + a bit more we can't account for */
2583 item->size=((item->cols_out-1)/8+1)*item->rows_out;
2585 #else
2587 /* this is pretty much the size of a RotatedTextItem */
2589 item->size=((item->cols_out-1)/8+1)*item->rows_out +
2590 sizeof(XImage) + strlen(item->text) +
2591 item->nl*8*sizeof(float) + sizeof(RotatedTextItem);
2593 if(item->font_name!=NULL)
2594 item->size+=strlen(item->font_name);
2595 else
2596 item->size+=sizeof(Font);
2598 #endif /*CACHE_BITMAPS */
2600 #ifdef DEBUG
2601 /* count number of items in cache, for debugging */
2603 int i=0;
2605 while(i1) {
2606 i++;
2607 i1=i1->next;
2609 DEBUG_PRINT2("Cache has %d items.\n", i);
2610 i1=first_text_item;
2612 #endif
2614 DEBUG_PRINT4("current cache size=%ld, new item=%ld, limit=%ld\n",
2615 current_size, item->size, CACHE_SIZE_LIMIT*1024);
2617 /* if this item is bigger than whole cache, forget it */
2618 if(item->size>CACHE_SIZE_LIMIT*1024) {
2619 DEBUG_PRINT1("Too big to cache\n\n");
2620 item->cached=0;
2621 return;
2624 /* remove elements from cache as needed */
2625 while(i1 && current_size+item->size>CACHE_SIZE_LIMIT*1024) {
2627 DEBUG_PRINT2("Removed %d bytes\n", i1->size);
2629 if(i1->font_name!=NULL)
2630 DEBUG_PRINT5(" (`%s'\n %s\n angle=%f align=%d)\n",
2631 i1->text, i1->font_name, i1->angle, i1->align);
2633 #ifdef CACHE_FID
2634 if(i1->font_name==NULL)
2635 DEBUG_PRINT5(" (`%s'\n FID=%ld\n angle=%f align=%d)\n",
2636 i1->text, i1->fid, i1->angle, i1->align);
2637 #endif /*CACHE_FID*/
2639 current_size-=i1->size;
2641 i2=i1->next;
2643 /* free resources used by the unlucky item */
2644 XRotFreeTextItem(dpy, i1);
2646 /* remove it from linked list */
2647 first_text_item=i2;
2648 i1=i2;
2651 /* add new item to end of linked list */
2652 if(first_text_item==NULL) {
2653 item->next=NULL;
2654 first_text_item=item;
2655 last=item;
2657 else {
2658 item->next=NULL;
2659 last->next=item;
2660 last=item;
2663 /* new cache size */
2664 current_size+=item->size;
2666 item->cached=1;
2668 DEBUG_PRINT1("Added item to cache.\n");
2672 /* ---------------------------------------------------------------------- */
2675 /**************************************************************************/
2676 /* Free the resources used by a text item */
2677 /**************************************************************************/
2679 static void XRotFreeTextItem(Display *dpy, RotatedTextItem *item)
2681 free(item->text);
2683 if(item->font_name!=NULL)
2684 free(item->font_name);
2686 free((char *)item->corners_x);
2687 free((char *)item->corners_y);
2689 #ifdef CACHE_BITMAPS
2690 XFreePixmap(dpy, item->bitmap);
2691 #else
2692 XDestroyImage(item->ximage);
2693 #endif /* CACHE_BITMAPS */
2695 free((char *)item);
2699 /* ---------------------------------------------------------------------- */
2702 /**************************************************************************/
2703 /* Magnify an XImage using bilinear interpolation */
2704 /**************************************************************************/
2706 static XImage *XRotMagnifyImage(Display *dpy, XImage *ximage)
2708 int i, j;
2709 float x, y;
2710 float u,t;
2711 XImage *I_out;
2712 int cols_in, rows_in;
2713 int cols_out, rows_out;
2714 register int i2, j2;
2715 float z1, z2, z3, z4;
2716 int byte_width_in, byte_width_out;
2717 float mag_inv;
2719 /* size of input image */
2720 cols_in=ximage->width;
2721 rows_in=ximage->height;
2723 /* size of final image */
2724 cols_out=(float)cols_in*style.magnify;
2725 rows_out=(float)rows_in*style.magnify;
2727 /* this will hold final image */
2728 I_out=MakeXImage(dpy, cols_out, rows_out);
2729 if(I_out==NULL)
2730 return NULL;
2732 /* width in bytes of input, output images */
2733 byte_width_in=(cols_in-1)/8+1;
2734 byte_width_out=(cols_out-1)/8+1;
2736 /* for speed */
2737 mag_inv=1./style.magnify;
2739 y=0.;
2741 /* loop over magnified image */
2742 for(j2=0; j2<rows_out; j2++) {
2743 x=0;
2744 j=y;
2746 for(i2=0; i2<cols_out; i2++) {
2747 i=x;
2749 /* bilinear interpolation - where are we on bitmap ? */
2750 /* right edge */
2751 if(i==cols_in-1 && j!=rows_in-1) {
2752 t=0;
2753 u=y-(float)j;
2755 z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
2756 z2=z1;
2757 z3=(ximage->data[(j+1)*byte_width_in+i/8] & 128>>(i%8))>0;
2758 z4=z3;
2760 /* top edge */
2761 else if(i!=cols_in-1 && j==rows_in-1) {
2762 t=x-(float)i;
2763 u=0;
2765 z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
2766 z2=(ximage->data[j*byte_width_in+(i+1)/8] & 128>>((i+1)%8))>0;
2767 z3=z2;
2768 z4=z1;
2770 /* top right corner */
2771 else if(i==cols_in-1 && j==rows_in-1) {
2772 u=0;
2773 t=0;
2775 z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
2776 z2=z1;
2777 z3=z1;
2778 z4=z1;
2780 /* somewhere `safe' */
2781 else {
2782 t=x-(float)i;
2783 u=y-(float)j;
2785 z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
2786 z2=(ximage->data[j*byte_width_in+(i+1)/8] & 128>>((i+1)%8))>0;
2787 z3=(ximage->data[(j+1)*byte_width_in+(i+1)/8] &
2788 128>>((i+1)%8))>0;
2789 z4=(ximage->data[(j+1)*byte_width_in+i/8] & 128>>(i%8))>0;
2792 /* if interpolated value is greater than 0.5, set bit */
2793 if(((1-t)*(1-u)*z1 + t*(1-u)*z2 + t*u*z3 + (1-t)*u*z4)>0.5)
2794 I_out->data[j2*byte_width_out+i2/8]|=128>>i2%8;
2796 x+=mag_inv;
2798 y+=mag_inv;
2801 /* destroy original */
2802 XDestroyImage(ximage);
2804 /* return big image */
2805 return I_out;
2810 /* ---------------------------------------------------------------------- */
2813 /**************************************************************************/
2814 /* Calculate the bounding box some text will have when painted */
2815 /**************************************************************************/
2816 static
2817 XPoint *XRotTextExtents(Display *dpy, XFontStruct *font, float angle, int x, int y, char *text, int align)
2819 register int i;
2820 char *str1, *str2, *str3;
2821 char *str2_a="\0", *str2_b="\n\0";
2822 int height;
2823 float sin_angle, cos_angle;
2824 int nl, max_width;
2825 int cols_in, rows_in;
2826 float hot_x, hot_y;
2827 XPoint *xp_in, *xp_out;
2828 int dir, asc, desc;
2829 XCharStruct overall;
2831 /* manipulate angle to 0<=angle<360 degrees */
2832 while(angle<0)
2833 angle+=360;
2835 while(angle>360)
2836 angle-=360;
2838 angle*=M_PI/180;
2840 /* count number of sections in string */
2841 nl=1;
2842 if(align!=NONE)
2843 for(i=0; i<strlen(text)-1; i++)
2844 if(text[i]=='\n')
2845 nl++;
2847 /* ignore newline characters if not doing alignment */
2848 if(align==NONE)
2849 str2=str2_a;
2850 else
2851 str2=str2_b;
2853 /* find width of longest section */
2854 str1=my_strdup(text);
2855 if(str1==NULL)
2856 return NULL;
2858 str3=my_strtok(str1, str2);
2860 XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
2861 &overall);
2863 max_width=overall.rbearing;
2865 /* loop through each section */
2866 do {
2867 str3=my_strtok((char *)NULL, str2);
2869 if(str3!=NULL) {
2870 XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
2871 &overall);
2873 if(overall.rbearing>max_width)
2874 max_width=overall.rbearing;
2877 while(str3!=NULL);
2879 free(str1);
2881 /* overall font height */
2882 height=font->ascent+font->descent;
2884 /* dimensions horizontal text will have */
2885 cols_in=max_width;
2886 rows_in=nl*height;
2888 /* pre-calculate sin and cos */
2889 sin_angle=sin(angle);
2890 cos_angle=cos(angle);
2892 /* y position */
2893 if(align==TLEFT || align==TCENTRE || align==TRIGHT)
2894 hot_y=(float)rows_in/2*style.magnify;
2895 else if(align==MLEFT || align==MCENTRE || align==MRIGHT)
2896 hot_y=0;
2897 else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
2898 hot_y = -(float)rows_in/2*style.magnify;
2899 else
2900 hot_y = -((float)rows_in/2-(float)font->descent)*style.magnify;
2902 /* x position */
2903 if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
2904 hot_x = -(float)max_width/2*style.magnify;
2905 else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
2906 hot_x=0;
2907 else
2908 hot_x=(float)max_width/2*style.magnify;
2910 /* reserve space for XPoints */
2911 xp_in=(XPoint *)malloc((unsigned)(5*sizeof(XPoint)));
2912 if(!xp_in)
2913 return NULL;
2915 xp_out=(XPoint *)malloc((unsigned)(5*sizeof(XPoint)));
2916 if(!xp_out)
2917 return NULL;
2919 /* bounding box when horizontal, relative to bitmap centre */
2920 xp_in[0].x = -(float)cols_in*style.magnify/2-style.bbx_pad;
2921 xp_in[0].y= (float)rows_in*style.magnify/2+style.bbx_pad;
2922 xp_in[1].x= (float)cols_in*style.magnify/2+style.bbx_pad;
2923 xp_in[1].y= (float)rows_in*style.magnify/2+style.bbx_pad;
2924 xp_in[2].x= (float)cols_in*style.magnify/2+style.bbx_pad;
2925 xp_in[2].y = -(float)rows_in*style.magnify/2-style.bbx_pad;
2926 xp_in[3].x = -(float)cols_in*style.magnify/2-style.bbx_pad;
2927 xp_in[3].y = -(float)rows_in*style.magnify/2-style.bbx_pad;
2928 xp_in[4].x=xp_in[0].x;
2929 xp_in[4].y=xp_in[0].y;
2931 /* rotate and translate bounding box */
2932 for(i=0; i<5; i++) {
2933 xp_out[i].x=(float)x + ( ((float)xp_in[i].x-hot_x)*cos_angle +
2934 ((float)xp_in[i].y+hot_y)*sin_angle);
2935 xp_out[i].y=(float)y + (-((float)xp_in[i].x-hot_x)*sin_angle +
2936 ((float)xp_in[i].y+hot_y)*cos_angle);
2939 free((char *)xp_in);
2941 return xp_out;
2946 /* ***********************************************************************
2947 * Conversion routines for the X resource manager
2948 * ***********************************************************************
2951 #if defined(__STDC__)
2952 static
2953 Boolean strtocard( Display *dsp,
2954 XrmValue *args,
2955 Cardinal *num_args,
2956 XrmValue *from,
2957 XrmValue *to,
2958 XtPointer *unused
2960 #else
2961 static
2962 Boolean strtocard( dsp, args, num_args, from, to, unused )
2963 Display *dsp;
2964 XrmValue *args;
2965 Cardinal *num_args;
2966 XrmValue *from;
2967 XrmValue *to;
2968 XtPointer *unused;
2969 #endif
2971 static Cardinal temp;
2973 if ( to->addr == NULL ) {
2974 to->addr = (XtPointer) &temp;
2975 to->size = sizeof(Cardinal);
2978 *((Cardinal *) to->addr) = atoi( from->addr );
2979 return True;
2983 #define done_bert(type, value) \
2984 do {\
2985 if (to->addr != NULL) {\
2986 if (to->size < sizeof(type)) {\
2987 to->size = sizeof(type);\
2988 return False;\
2990 *(type*)(to->addr) = (value);\
2991 } else {\
2992 static type static_val;\
2993 static_val = (value);\
2994 to->addr = (XtPointer)&static_val;\
2996 to->size = sizeof(type);\
2997 return True;\
2998 } while (0)
2999 static
3000 Boolean cvtStringToStringArray(Display *display, XrmValuePtr args, Cardinal *num_args, XrmValuePtr from, XrmValuePtr to, XtPointer *converter_data)
3002 String t, s;
3003 StringArray a = NULL;
3004 Cardinal i;
3005 char delim;
3007 if (*num_args != 0)
3008 XtAppErrorMsg(XtDisplayToApplicationContext(display),
3009 "cvtStringToStringArray", "wrongParameters",
3010 "XtToolkitError",
3011 "String to StringArray conversion needs no arguments",
3012 (String*) NULL, (Cardinal*) NULL);
3014 delim = ((String) from->addr)[0];
3015 s = XtNewString((String) from->addr + 1);
3016 i = 0;
3017 while (s && *s) {
3018 t = strchr(s, delim);
3019 if (t) *t = '\0';
3020 a = (StringArray) XtRealloc((String) a, (i + 1) * sizeof(*a));
3021 a[i] = s;
3022 i++;
3023 s = t ? t + 1 : NULL;
3025 a = (StringArray) XtRealloc((String) a, (i + 1) * sizeof(*a));
3026 a[i] = NULL;
3027 done_bert(StringArray, a);
3031 /* ***********************************************************************
3032 * A driver for the above in the flavor of the xt utilities module
3033 * ***********************************************************************
3036 #define TABHT 25
3038 typedef struct tab_data {
3039 Widget form;
3040 int cur,
3041 num_tabs;
3042 void (*activate_func)();
3043 } *TabData;
3046 #if defined(__STDC__)
3047 static void handle_click( Widget w, TabData td, XtPointer call_data )
3048 #else
3049 static void handle_click(w, td, call_data)
3050 Widget w;
3051 TabData td;
3052 XtPointer call_data;
3053 #endif
3055 int tab = (int) call_data;
3057 /* note that the tab is relative to the current tab.
3058 * if tab is 0, the user clicked on the current one.
3059 * there is nothing to do
3061 if (tab == 0) return;
3062 td->cur += tab;
3064 /* Change tabs. We must manually inform the UI which tab is current */
3065 XtVaSetValues( w,
3066 XtNlefttabs, td->cur,
3067 XtNrighttabs, td->num_tabs - td->cur - 1,
3068 NULL
3071 (*td->activate_func)( td->form, td->cur );
3076 * PUBLIC: Widget __vi_CreateTabbedFolder
3077 * PUBLIC: __P((String, Widget, String, int, void (*)(Widget, int)));
3079 #if defined(__STDC__)
3080 Widget __vi_CreateTabbedFolder( String name,
3081 Widget parent,
3082 String tab_labels,
3083 int num_tabs,
3084 void (*activate_func)()
3086 #else
3087 Widget __vi_CreateTabbedFolder( name, parent, tab_labels, num_tabs, activate_func )
3088 String name;
3089 String tab_labels;
3090 Widget parent;
3091 int num_tabs;
3092 void (*activate_func)();
3093 #endif
3095 Widget tabs;
3096 TabData td = (TabData) malloc( sizeof(struct tab_data) );
3097 int i;
3099 XtAppSetTypeConverter( XtDisplayToApplicationContext(XtDisplay(parent)),
3100 XtRString,
3101 XtRCardinal,
3102 strtocard,
3103 NULL,
3105 XtCacheNone,
3106 NULL
3109 /* init our internal structure */
3110 td->cur = 0;
3111 td->num_tabs = num_tabs;
3112 td->activate_func = activate_func;
3114 /* tabs go on the top */
3115 tabs = XtVaCreateManagedWidget( "tabs",
3116 xmTabsWidgetClass,
3117 parent,
3118 XtNlefttabs, 0,
3119 XtNrighttabs, num_tabs-1,
3120 XtNorientation, XfwfUpTabs,
3121 XmNtopAttachment, XmATTACH_FORM,
3122 XmNleftAttachment, XmATTACH_FORM,
3123 XmNleftOffset, TABHT/4,
3124 XmNrightAttachment,XmATTACH_FORM,
3125 XmNrightOffset, TABHT/4,
3126 XmNbottomAttachment,XmATTACH_OPPOSITE_FORM,
3127 XmNbottomOffset, -TABHT,
3128 XtNlabels, tab_labels,
3129 XtVaTypedArg, XtNlabels,
3130 XtRString,
3131 tab_labels,
3132 strlen(tab_labels) + 1,
3133 NULL
3136 /* add the callback */
3137 XtAddCallback( tabs,
3138 XtNactivateCallback,
3139 (XtCallbackProc) handle_click,
3143 /* another form to hold the controls */
3144 td->form = XtVaCreateWidget( "form",
3145 xmFormWidgetClass,
3146 parent,
3147 XmNtopAttachment, XmATTACH_WIDGET,
3148 XmNtopWidget, tabs,
3149 XmNleftAttachment, XmATTACH_FORM,
3150 XmNbottomAttachment, XmATTACH_FORM,
3151 XmNrightAttachment, XmATTACH_FORM,
3152 NULL
3155 /* done */
3156 return td->form;