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 * ***********************************************************************
20 #include <Xm/RowColumn.h>
21 #include <X11/StringDefs.h>
22 #include <X11/IntrinsicP.h>
24 #include <DECW$INCLUDE/shape.h>
26 #include <X11/extensions/shape.h>
29 #include <X11/Xutil.h>
30 #include <X11/Xatom.h>
34 /* ***********************************************************************
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 /* ---------------------------------------------------------------------- */
75 /* ---------------------------------------------------------------------- */
77 /* this shoulf be C++ compliant, thanks to
78 vlp@latina.inesc.pt (Vasco Lopes Paulo) */
80 #if defined(__cplusplus) || defined(c_plusplus)
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);
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 /* ***********************************************************************
121 * ***********************************************************************
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
142 The delimiter character is the first character in the string.
147 The function |newStringArray| makes a copy of a |StringArray|. It
148 allocates new space for the array itself and for the strings that
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
171 XtPointer
*converter_data
176 StringArray
newStringArray(
177 #if NeedFunctionPrototypes
183 void freeStringArray(
184 #if NeedFunctionPrototypes
190 #endif /* _strarray_h_ */
193 /* ***********************************************************************
195 * ***********************************************************************
198 /* Generated by wbuild from "XmTabs.w"
199 ** (generator version Revision: 8.5 of Date: 2001/06/25 15:19:28)
204 XfwfUpTabs
, XfwfDownTabs
, XfwfLeftTabs
, XfwfRightTabs
,
207 #ifndef XtNorientation
208 #define XtNorientation "orientation"
210 #ifndef XtCOrientation
211 #define XtCOrientation "Orientation"
213 #ifndef XtRTabsOrientation
214 #define XtRTabsOrientation "TabsOrientation"
218 #define XtNlefttabs "lefttabs"
221 #define XtCLefttabs "Lefttabs"
228 #define XtNrighttabs "righttabs"
231 #define XtCRighttabs "Righttabs"
238 #define XtNlabels "labels"
241 #define XtCLabels "Labels"
243 #ifndef XtRStringArray
244 #define XtRStringArray "StringArray"
247 #ifndef XtNtabWidthPercentage
248 #define XtNtabWidthPercentage "tabWidthPercentage"
250 #ifndef XtCTabWidthPercentage
251 #define XtCTabWidthPercentage "TabWidthPercentage"
257 #ifndef XtNcornerwidth
258 #define XtNcornerwidth "cornerwidth"
260 #ifndef XtCCornerwidth
261 #define XtCCornerwidth "Cornerwidth"
264 #define XtRCardinal "Cardinal"
267 #ifndef XtNcornerheight
268 #define XtNcornerheight "cornerheight"
270 #ifndef XtCCornerheight
271 #define XtCCornerheight "Cornerheight"
274 #define XtRCardinal "Cardinal"
277 #ifndef XtNtextmargin
278 #define XtNtextmargin "textmargin"
280 #ifndef XtCTextmargin
281 #define XtCTextmargin "Textmargin"
288 #define XtNtabcolor "tabcolor"
291 #define XtCTabcolor "Tabcolor"
294 #define XtRPixel "Pixel"
298 #define XtNfont "font"
301 #define XtCFont "Font"
303 #ifndef XtRFontStruct
304 #define XtRFontStruct "FontStruct"
307 #ifndef XtNactivateCallback
308 #define XtNactivateCallback "activateCallback"
310 #ifndef XtCActivateCallback
311 #define XtCActivateCallback "ActivateCallback"
314 #define XtRCallback "Callback"
317 typedef struct _XmTabsClassRec
*XmTabsWidgetClass
;
318 typedef struct _XmTabsRec
*XmTabsWidget
;
319 #endif /*_XmTabs_H_*/
322 /* ***********************************************************************
324 * ***********************************************************************
327 /* Generated by wbuild from "XmTabs.w"
328 ** (generator version Revision: 8.5 of Date: 2001/06/25 15:19:28)
333 /* raz modified 22 Jul 96 for bluestone */
335 #if ! defined(MGR_ShadowThickness)
336 #include <Xm/ManagerP.h>
339 typedef void (*border_highlight_Proc
)(
340 #if NeedFunctionPrototypes
344 #define XtInherit_border_highlight ((border_highlight_Proc) _XtInherit)
345 typedef void (*border_unhighlight_Proc
)(
346 #if NeedFunctionPrototypes
350 #define XtInherit_border_unhighlight ((border_unhighlight_Proc) _XtInherit)
352 /* Constraint resources */
353 /* Private constraint variables */
355 } XmTabsConstraintPart
;
357 typedef struct _XmTabsConstraintRec
{
358 XmManagerConstraintPart xmManager
;
359 XmTabsConstraintPart xmTabs
;
360 } XmTabsConstraintRec
;
365 border_highlight_Proc border_highlight
;
366 border_unhighlight_Proc border_unhighlight
;
367 /* class variables */
370 typedef struct _XmTabsClassRec
{
371 CoreClassPart core_class
;
372 CompositeClassPart composite_class
;
373 ConstraintClassPart constraint_class
;
374 XmManagerClassPart xmManager_class
;
375 XmTabsClassPart xmTabs_class
;
380 TabsOrientation orientation
;
384 int tabWidthPercentage
;
385 Cardinal cornerwidth
;
386 Cardinal cornerheight
;
390 XtCallbackList activateCallback
;
401 typedef struct _XmTabsRec
{
403 CompositePart composite
;
404 ConstraintPart constraint
;
405 XmManagerPart xmManager
;
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
*
423 static XtActionsRec actionsList
[] = {
424 {"activate", activate
},
427 static char defaultTranslations
[] = "\
428 <Btn1Down>,<Btn1Up>: activate() \n\
430 static void _resolve_inheritance(
431 #if NeedFunctionPrototypes
435 static void class_initialize(
436 #if NeedFunctionPrototypes
440 static void initialize(
441 #if NeedFunctionPrototypes
442 Widget
,Widget
,ArgList
,Cardinal
*
445 static Boolean
set_values(
446 #if NeedFunctionPrototypes
447 Widget
,Widget
,Widget
,ArgList
,Cardinal
*
451 #if NeedFunctionPrototypes
452 Widget
,XtValueMask
*,XSetWindowAttributes
*
456 #if NeedFunctionPrototypes
461 #if NeedFunctionPrototypes
462 Widget
,XEvent
*,Region
465 static void border_highlight(
466 #if NeedFunctionPrototypes
470 static void border_unhighlight(
471 #if NeedFunctionPrototypes
476 #if NeedFunctionPrototypes
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
491 static void comp_hor_tab_shape(
492 #if NeedFunctionPrototypes
493 Widget
,int ,XPoint p
[12],int *,int *,int *
496 static void comp_ver_tab_shape(
497 #if NeedFunctionPrototypes
498 Widget
,int ,XPoint p
[12],int *,int *,int *
501 static void draw_border(
502 #if NeedFunctionPrototypes
503 Widget
,XPoint poly
[12]
506 static void draw_hor_tab(
507 #if NeedFunctionPrototypes
511 static void draw_ver_tab(
512 #if NeedFunctionPrototypes
516 static void create_topgc(
517 #if NeedFunctionPrototypes
521 static void create_bottomgc(
522 #if NeedFunctionPrototypes
526 static void create_textgc(
527 #if NeedFunctionPrototypes
531 static void create_fillgc(
532 #if NeedFunctionPrototypes
536 static void create_backgc(
537 #if NeedFunctionPrototypes
542 #if NeedFunctionPrototypes
543 Widget
,int ,XrmValue
*
546 static void set_shape(
547 #if NeedFunctionPrototypes
551 #define done(type, value) do {\
552 if (to->addr != NULL) {\
553 if (to->size < sizeof(type)) {\
554 to->size = sizeof(type);\
557 *(type*)(to->addr) = (value);\
559 static type static_val;\
560 static_val = (value);\
561 to->addr = (XtPointer)&static_val;\
563 to->size = sizeof(type);\
568 static Boolean
cvtStringToTabsOrientation(
569 #if NeedFunctionPrototypes
570 Display
*,XrmValuePtr
,Cardinal
*,XrmValuePtr
,XrmValuePtr
,XtPointer
*
573 static Boolean
cvtTabsOrientationToString(
574 #if NeedFunctionPrototypes
575 Display
*,XrmValuePtr
,Cardinal
*,XrmValuePtr
,XrmValuePtr
,XtPointer
*
579 #if NeedFunctionPrototypes
580 static void compute_tabsizes(Widget self
)
582 static void compute_tabsizes(self
)Widget self
;
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
;
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 */
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;
625 delta
= (length
- sum
)/(n
- 1); /* Between tabs */
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
;
633 #if NeedFunctionPrototypes
634 static void comp_hor_tab_shape(Widget self
,int i
,XPoint p
[12],int * x0
,int * x1
,int * midy
)
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
;
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
648 * 0 o--------o o--------o 9
649 * 11 o---------------------------------------o 10
651 * 11 o---------------------------------------o 10
652 * 0 o--------o o--------o 9
658 * 4 o-------------o 5
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
;
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
;
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
;
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
;
702 *midy
= (p
[1].y
+ p
[4].y
)/2;
705 #if NeedFunctionPrototypes
706 static void comp_ver_tab_shape(Widget self
,int i
,XPoint p
[12],int * y0
,int * y1
,int * midx
)
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
;
711 int shad
= ((XmTabsWidget
)self
)->xmManager
.shadow_thickness
;
712 int k
= min(((XmTabsWidget
)self
)->xmTabs
.cornerheight
, (((XmTabsWidget
)self
)->core
.width
- shad
)/2);
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
;
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
;
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
;
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
;
771 *midx
= (p
[1].x
+ p
[4].x
)/2;
774 #if NeedFunctionPrototypes
775 static void draw_border(Widget self
,XPoint poly
[12])
777 static void draw_border(self
,poly
)Widget self
;XPoint poly
[12];
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
);
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
);
794 #if NeedFunctionPrototypes
795 static void draw_hor_tab(Widget self
,Region region
,int i
)
797 static void draw_hor_tab(self
,region
,i
)Widget self
;Region region
;int i
;
801 Display
*dpy
= XtDisplay(self
);
802 Window win
= XtWindow(self
);
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
);
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 */
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
);
840 #if NeedFunctionPrototypes
841 static void draw_ver_tab(Widget self
,Region region
,int i
)
843 static void draw_ver_tab(self
,region
,i
)Widget self
;Region region
;int i
;
846 Display
*dpy
= XtDisplay(self
);
847 Window win
= XtWindow(self
);
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
);
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
) {
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)) {
876 } else if (i
< ((XmTabsWidget
)self
)->xmTabs
.lefttabs
) {
877 y
= y0
+ ((XmTabsWidget
)self
)->xmTabs
.textmargin
;
878 align
= ((XmTabsWidget
)self
)->xmTabs
.orientation
== XfwfLeftTabs
? MRIGHT
: MLEFT
;
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
);
890 #if NeedFunctionPrototypes
891 static void create_topgc(Widget self
)
893 static void create_topgc(self
)Widget self
;
896 XtGCMask mask
= GCForeground
| GCLineWidth
;
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
)),
906 #if NeedFunctionPrototypes
907 static void create_bottomgc(Widget self
)
909 static void create_bottomgc(self
)Widget self
;
912 XtGCMask mask
= GCForeground
| GCLineWidth
;
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
)),
922 #if NeedFunctionPrototypes
923 static void create_textgc(Widget self
)
925 static void create_textgc(self
)Widget self
;
928 XtGCMask mask
= GCForeground
| GCFont
;
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
)),
938 #if NeedFunctionPrototypes
939 static void create_fillgc(Widget self
)
941 static void create_fillgc(self
)Widget self
;
944 XtGCMask mask
= GCForeground
;
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
)),
953 #if NeedFunctionPrototypes
954 static void create_backgc(Widget self
)
956 static void create_backgc(self
)Widget self
;
959 XtGCMask mask
= GCForeground
;
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
)),
968 #if NeedFunctionPrototypes
969 static void copy_bg(Widget self
,int offset
,XrmValue
* value
)
971 static void copy_bg(self
,offset
,value
)Widget self
;int offset
;XrmValue
* value
;
974 value
->addr
= (XtPointer
) &((XmTabsWidget
)self
)->core
.background_pixel
;
977 #if NeedFunctionPrototypes
978 static void set_shape(Widget self
)
980 static void set_shape(self
)Widget self
;
983 int x0
, x1
, midy
, y0
, y1
, midx
, i
;
987 if (! XtIsRealized(self
)) return;
989 region
= XCreateRegion();
991 switch (((XmTabsWidget
)self
)->xmTabs
.orientation
) {
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
);
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
);
1011 XShapeCombineRegion(XtDisplay(self
), XtWindow(self
), ShapeBounding
,
1012 0, 0, region
, ShapeSet
);
1013 XDestroyRegion(region
);
1017 #if NeedFunctionPrototypes
1018 static Boolean
cvtStringToTabsOrientation(Display
* display
,XrmValuePtr args
,Cardinal
* num_args
,XrmValuePtr from
,XrmValuePtr to
,XtPointer
* converter_data
)
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
;
1023 TabsOrientation a
= XfwfUpTabs
;
1024 char *s
= (char*) from
->addr
;
1027 TabsOrientation orient
;
1029 { "up", XfwfUpTabs
},
1030 { "uptabs", XfwfUpTabs
},
1031 { "down", XfwfDownTabs
},
1032 { "downtabs", XfwfDownTabs
},
1033 { "left", XfwfLeftTabs
},
1034 { "lefttabs", XfwfLeftTabs
},
1035 { "right", XfwfRightTabs
},
1036 { "righttabs", XfwfRightTabs
},
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
;
1053 if ( i
>= XtNumber(strings
) )
1054 XtDisplayStringConversionWarning(display
, s
, "TabsOrientation");
1055 done(TabsOrientation
, a
);
1058 #if NeedFunctionPrototypes
1059 static Boolean
cvtTabsOrientationToString(Display
* display
,XrmValuePtr args
,Cardinal
* num_args
,XrmValuePtr from
,XrmValuePtr to
,XtPointer
* converter_data
)
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
;
1064 TabsOrientation
*a
= (TabsOrientation
*) from
->addr
;
1068 (XtDisplayToApplicationContext(display
),
1069 "cvtTabsOrientationToString", "wrongParameters", "XtToolkitError",
1070 "TabsOrientation to String conversion needs no arguments",
1071 (String
*) NULL
, (Cardinal
*) NULL
);
1073 case XfwfUpTabs
: done(String
, "up");
1074 case XfwfDownTabs
: done(String
, "down");
1075 case XfwfLeftTabs
: done(String
, "left");
1076 case XfwfRightTabs
: done(String
, "right");
1079 (XtDisplayToApplicationContext(display
),
1080 "cvtTabsOrientationToString", "illParameters", "XtToolkitError",
1081 "TabsOrientation to String conversion got illegal argument",
1082 (String
*) NULL
, (Cardinal
*) NULL
);
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
,
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 */
1166 WidgetClass xmTabsWidgetClass
= (WidgetClass
) &xmTabsClassRec
;
1168 static void activate(Widget self
, XEvent
*event
, String
*params
, Cardinal
*num_params
)
1170 int x0
, x1
, dummy
, i
, x
, y
;
1173 switch (((XmTabsWidget
)self
)->xmTabs
.orientation
) {
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);
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
);
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
);
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);
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
);
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
);
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
;
1243 #if NeedFunctionPrototypes
1244 static void class_initialize(void)
1246 static void class_initialize(void)
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
);
1260 #if NeedFunctionPrototypes
1261 static void initialize(Widget request
,Widget self
,ArgList args
,Cardinal
* num_args
)
1263 static void initialize(request
,self
,args
,num_args
)Widget request
;Widget self
;ArgList args
;Cardinal
* num_args
;
1269 ((XmTabsWidget
)self
)->xmManager
.traversal_on
= FALSE
;
1270 ((XmTabsWidget
)self
)->xmTabs
.topgc
= NULL
;
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
);
1296 #if NeedFunctionPrototypes
1297 static Boolean
set_values(Widget old
,Widget request
,Widget self
,ArgList args
,Cardinal
* num_args
)
1299 static Boolean
set_values(old
,request
,self
,args
,num_args
)Widget old
;Widget request
;Widget self
;ArgList args
;Cardinal
* num_args
;
1302 Bool redraw
= FALSE
, resize_labels
= FALSE
;
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
) {
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
);
1317 if (((XmTabsWidget
)self
)->xmTabs
.tabcolor
!= ((XmTabsWidget
)old
)->xmTabs
.tabcolor
) {
1318 create_fillgc(self
);
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
)
1349 if (resize_labels
) {
1350 compute_tabsizes(self
);
1356 #if NeedFunctionPrototypes
1357 static void realize(Widget self
,XtValueMask
* mask
,XSetWindowAttributes
* attributes
)
1359 static void realize(self
,mask
,attributes
)Widget self
;XtValueMask
* mask
;XSetWindowAttributes
* attributes
;
1362 *mask
|= CWBitGravity
;
1363 attributes
->bit_gravity
= ForgetGravity
;
1364 xmManagerClassRec
.core_class
.realize(self
, mask
, attributes
);
1368 #if NeedFunctionPrototypes
1369 static void resize(Widget self
)
1371 static void resize(self
)Widget self
;
1374 if (XtIsRealized(self
))
1375 XClearArea(XtDisplay(self
), XtWindow(self
), 0, 0, 0, 0, True
);
1376 compute_tabsizes(self
);
1378 if ( xmManagerClassRec
.core_class
.resize
) xmManagerClassRec
.core_class
.resize(self
);
1381 #if NeedFunctionPrototypes
1382 static void expose(Widget self
,XEvent
* event
,Region region
)
1384 static void expose(self
,event
,region
)Widget self
;XEvent
* event
;Region region
;
1389 if (! XtIsRealized(self
)) return;
1391 switch (((XmTabsWidget
)self
)->xmTabs
.orientation
) {
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
);
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
);
1409 /* Focus highlight? */
1412 #if NeedFunctionPrototypes
1413 static void border_highlight(void)
1415 static void border_highlight(void)
1420 #if NeedFunctionPrototypes
1421 static void border_unhighlight(void)
1423 static void border_unhighlight(void)
1428 #if NeedFunctionPrototypes
1429 static void destroy(Widget self
)
1431 static void destroy(self
)Widget self
;
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 */
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 /* ---------------------------------------------------------------------- */
1520 #define M_PI 3.14159265358979323846
1524 /* ---------------------------------------------------------------------- */
1527 /* A structure holding everything needed for a rotated string */
1529 typedef struct rotated_text_item_template
{
1553 struct rotated_text_item_template
*next
;
1556 RotatedTextItem
*first_text_item
=NULL
;
1559 /* ---------------------------------------------------------------------- */
1562 /* A structure holding current magnification and bounding box padding */
1564 static struct style_template
{
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
)
1612 s
=(char *)malloc((unsigned)(strlen(str
)+1));
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
)
1632 static int start
, len
;
1638 /* initialise if str1 not NULL */
1645 /* run out of tokens ? */
1649 /* loop through characters */
1650 for(i
=start
; i
<len
; i
++) {
1651 /* loop through delimiters */
1653 for(j
=0; j
<strlen(str2
); j
++)
1654 if(stext
[i
]==str2
[j
])
1671 /* ---------------------------------------------------------------------- */
1674 /**************************************************************************/
1675 /* Return version/copyright information */
1676 /**************************************************************************/
1678 float XRotVersion(char *str
, int n
)
1681 strncpy(str
, XV_COPYRIGHT
, n
);
1686 /* ---------------------------------------------------------------------- */
1689 /**************************************************************************/
1690 /* Set the font magnification factor for all subsequent operations */
1691 /**************************************************************************/
1693 void XRotSetMagnification(float m
)
1700 /* ---------------------------------------------------------------------- */
1703 /**************************************************************************/
1704 /* Set the padding used when calculating bounding boxes */
1705 /**************************************************************************/
1707 void XRotSetBoundingBoxPad(int p
)
1714 /* ---------------------------------------------------------------------- */
1717 /**************************************************************************/
1718 /* Create an XImage structure and allocate memory for it */
1719 /**************************************************************************/
1721 static XImage
*MakeXImage(Display
*dpy
, int w
, int h
)
1726 /* reserve memory for image */
1727 data
=(char *)calloc((unsigned)(((w
-1)/8+1)*h
), 1);
1731 /* create the XImage */
1732 I
=XCreateImage(dpy
, DefaultVisual(dpy
, DefaultScreen(dpy
)), 1, XYBitmap
,
1733 0, data
, w
, h
, 8, 0);
1737 I
->byte_order
=I
->bitmap_bit_order
=MSBFirst
;
1742 /* ---------------------------------------------------------------------- */
1745 /**************************************************************************/
1746 /* A front end to XRotPaintAlignedString: */
1747 /* -no alignment, no background */
1748 /**************************************************************************/
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 /**************************************************************************/
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 /**************************************************************************/
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 /**************************************************************************/
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
)
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 */
1827 /* manipulate angle to 0<=angle<360 degrees */
1836 /* horizontal text made easy */
1837 if(angle
==0. && style
.magnify
==1.)
1838 return(XRotDrawHorizontalString(dpy
, font
, drawable
, gc
, x
, y
,
1841 /* get a rotated bitmap */
1842 item
=XRotRetrieveFromCache(dpy
, font
, angle
, text
, align
);
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? */
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
)
1859 else if(align
==BLEFT
|| align
==BCENTRE
|| align
==BRIGHT
)
1860 hot_y
= -(float)item
->rows_in
/2*style
.magnify
;
1862 hot_y
= -((float)item
->rows_in
/2-(float)font
->descent
)*style
.magnify
;
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
)
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 */
1884 Pixmap empty_stipple
;
1886 /* reserve space for XPoints */
1887 xpoints
=(XPoint
*)malloc((unsigned)(4*item
->nl
*sizeof(XPoint
)));
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
,
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 */
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
,
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);
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);
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
;
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 */
2027 XRotFreeTextItem(dpy
,item
);
2029 /* we got to the end OK! */
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
)
2047 char *str1
, *str2
, *str3
;
2048 char *str2_a
="\0", *str2_b
="\n\0";
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);
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 */
2064 for(i
=0; i
<strlen(text
)-1; i
++)
2068 /* ignore newline characters if not doing alignment */
2074 /* overall font height */
2075 height
=font
->ascent
+font
->descent
;
2078 if(align
==TLEFT
|| align
==TCENTRE
|| align
==TRIGHT
)
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
;
2087 str1
=my_strdup(text
);
2091 str3
=my_strtok(str1
, str2
);
2093 /* loop through each section in the string */
2095 XTextExtents(font
, str3
, strlen(str3
), &dir
, &asc
, &desc
,
2098 /* where to draw section in x ? */
2099 if(align
==TLEFT
|| align
==MLEFT
|| align
==BLEFT
|| align
==NONE
)
2101 else if(align
==TCENTRE
|| align
==MCENTRE
|| align
==BCENTRE
)
2102 xp
=x
-overall
.rbearing
/2;
2104 xp
=x
-overall
.rbearing
;
2106 /* draw string onto bitmap */
2108 XDrawString(dpy
, drawable
, my_gc
, xp
, yp
, str3
, strlen(str3
));
2110 XDrawImageString(dpy
, drawable
, my_gc
, xp
, yp
, str3
, strlen(str3
));
2112 /* move to next line */
2115 str3
=my_strtok((char *)NULL
, str2
);
2120 XFreeGC(dpy
, my_gc
);
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
)
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
);
2149 /* otherwise rely (unreliably?) on font ID */
2151 DEBUG_PRINT1("can't get fontname, caching FID\n");
2156 /* not allowed to cache font ID's */
2158 DEBUG_PRINT1("can't get fontname, can't cache\n");
2162 #endif /*CACHE_FID*/
2164 /* look for a match in cache */
2166 /* matching formula:
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
&&
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) {
2186 DEBUG_PRINT1("Matched against font names\n");
2192 else if(font_name
==NULL
&& i1
->font_name
==NULL
) {
2195 DEBUG_PRINT1("Matched against FID's\n");
2200 #endif /*CACHE_FID*/
2209 DEBUG_PRINT1("**\nFound target in cache.\n");
2211 DEBUG_PRINT1("**\nNo match in cache.\n");
2215 /* create new item */
2216 item
=XRotCreateTextItem(dpy
, font
, angle
, text
, align
);
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
);
2229 item
->font_name
=NULL
;
2235 item
->magnify
=style
.magnify
;
2238 XRotAddToLinkedList(dpy
, item
);
2244 /* if XImage is cached, need to recreate the bitmap */
2246 #ifdef CACHE_XIMAGES
2250 /* create bitmap to hold rotated text */
2251 item
->bitmap
=XCreatePixmap(dpy
, DefaultRootWindow(dpy
),
2252 item
->cols_out
, item
->rows_out
, 1);
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*/
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
;
2285 char *str1
, *str2
, *str3
;
2286 char *str2_a
="\0", *str2_b
="\n\0";
2288 int byte_w_in
, byte_w_out
;
2290 float sin_angle
, cos_angle
;
2297 XCharStruct overall
;
2298 int old_cols_in
=0, old_rows_in
=0;
2300 /* allocate memory */
2301 item
=(RotatedTextItem
*)malloc((unsigned)sizeof(RotatedTextItem
));
2305 /* count number of sections in string */
2308 for(i
=0; i
<strlen(text
)-1; i
++)
2312 /* ignore newline characters if not doing alignment */
2318 /* find width of longest section */
2319 str1
=my_strdup(text
);
2323 str3
=my_strtok(str1
, str2
);
2325 XTextExtents(font
, str3
, strlen(str3
), &dir
, &asc
, &desc
,
2328 item
->max_width
=overall
.rbearing
;
2330 /* loop through each section */
2332 str3
=my_strtok((char *)NULL
, str2
);
2335 XTextExtents(font
, str3
, strlen(str3
), &dir
, &asc
, &desc
,
2338 if(overall
.rbearing
>item
->max_width
)
2339 item
->max_width
=overall
.rbearing
;
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 */
2374 (float *)malloc((unsigned)(4*item
->nl
*sizeof(float)));
2375 if(!item
->corners_x
)
2379 (float *)malloc((unsigned)(4*item
->nl
*sizeof(float)));
2380 if(!item
->corners_y
)
2383 /* draw text horizontally */
2385 /* start at top of bitmap */
2388 str1
=my_strdup(text
);
2392 str3
=my_strtok(str1
, str2
);
2394 /* loop through each section in the string */
2396 XTextExtents(font
, str3
, strlen(str3
), &dir
, &asc
, &desc
,
2399 /* where to draw section in x ? */
2400 if(align
==TLEFT
|| align
==MLEFT
|| align
==BLEFT
|| align
==NONE
)
2402 else if(align
==TCENTRE
|| align
==MCENTRE
|| align
==BCENTRE
)
2403 xp
=(item
->max_width
-overall
.rbearing
)/2;
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)
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];
2425 /* move to next line */
2428 str3
=my_strtok((char *)NULL
, str2
);
2434 /* create image to hold horizontal text */
2435 I_in
=MakeXImage(dpy
, item
->cols_in
, item
->rows_in
);
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)
2464 if(item
->rows_out
%2==0)
2467 /* create image to hold rotated text */
2468 item
->ximage
=MakeXImage(dpy
, item
->cols_out
, item
->rows_out
);
2469 if(item
->ximage
==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) {
2485 xr
=(float)item
->cols_out
;
2488 else if(angle
<M_PI
) {
2489 xl
=(float)item
->cols_out
/2+
2490 (dj
-(float)item
->rows_in
/(2*cos_angle
))/
2492 xr
=(float)item
->cols_out
/2+
2493 (dj
+(float)item
->rows_in
/(2*cos_angle
))/
2498 xl
=(float)item
->cols_out
/2+
2499 (dj
+(float)item
->rows_in
/(2*cos_angle
))/
2501 xr
=(float)item
->cols_out
/2+
2502 (dj
-(float)item
->rows_in
/(2*cos_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;
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
);
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
;
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
);
2596 item
->size
+=sizeof(Font
);
2598 #endif /*CACHE_BITMAPS */
2601 /* count number of items in cache, for debugging */
2609 DEBUG_PRINT2("Cache has %d items.\n", i
);
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");
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
);
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
;
2643 /* free resources used by the unlucky item */
2644 XRotFreeTextItem(dpy
, i1
);
2646 /* remove it from linked list */
2651 /* add new item to end of linked list */
2652 if(first_text_item
==NULL
) {
2654 first_text_item
=item
;
2663 /* new cache size */
2664 current_size
+=item
->size
;
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
)
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
);
2692 XDestroyImage(item
->ximage
);
2693 #endif /* CACHE_BITMAPS */
2699 /* ---------------------------------------------------------------------- */
2702 /**************************************************************************/
2703 /* Magnify an XImage using bilinear interpolation */
2704 /**************************************************************************/
2706 static XImage
*XRotMagnifyImage(Display
*dpy
, XImage
*ximage
)
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
;
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
);
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;
2737 mag_inv
=1./style
.magnify
;
2741 /* loop over magnified image */
2742 for(j2
=0; j2
<rows_out
; j2
++) {
2746 for(i2
=0; i2
<cols_out
; i2
++) {
2749 /* bilinear interpolation - where are we on bitmap ? */
2751 if(i
==cols_in
-1 && j
!=rows_in
-1) {
2755 z1
=(ximage
->data
[j
*byte_width_in
+i
/8] & 128>>(i
%8))>0;
2757 z3
=(ximage
->data
[(j
+1)*byte_width_in
+i
/8] & 128>>(i
%8))>0;
2761 else if(i
!=cols_in
-1 && j
==rows_in
-1) {
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;
2770 /* top right corner */
2771 else if(i
==cols_in
-1 && j
==rows_in
-1) {
2775 z1
=(ximage
->data
[j
*byte_width_in
+i
/8] & 128>>(i
%8))>0;
2780 /* somewhere `safe' */
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] &
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;
2801 /* destroy original */
2802 XDestroyImage(ximage
);
2804 /* return big image */
2810 /* ---------------------------------------------------------------------- */
2813 /**************************************************************************/
2814 /* Calculate the bounding box some text will have when painted */
2815 /**************************************************************************/
2817 XPoint
*XRotTextExtents(Display
*dpy
, XFontStruct
*font
, float angle
, int x
, int y
, char *text
, int align
)
2820 char *str1
, *str2
, *str3
;
2821 char *str2_a
="\0", *str2_b
="\n\0";
2823 float sin_angle
, cos_angle
;
2825 int cols_in
, rows_in
;
2827 XPoint
*xp_in
, *xp_out
;
2829 XCharStruct overall
;
2831 /* manipulate angle to 0<=angle<360 degrees */
2840 /* count number of sections in string */
2843 for(i
=0; i
<strlen(text
)-1; i
++)
2847 /* ignore newline characters if not doing alignment */
2853 /* find width of longest section */
2854 str1
=my_strdup(text
);
2858 str3
=my_strtok(str1
, str2
);
2860 XTextExtents(font
, str3
, strlen(str3
), &dir
, &asc
, &desc
,
2863 max_width
=overall
.rbearing
;
2865 /* loop through each section */
2867 str3
=my_strtok((char *)NULL
, str2
);
2870 XTextExtents(font
, str3
, strlen(str3
), &dir
, &asc
, &desc
,
2873 if(overall
.rbearing
>max_width
)
2874 max_width
=overall
.rbearing
;
2881 /* overall font height */
2882 height
=font
->ascent
+font
->descent
;
2884 /* dimensions horizontal text will have */
2888 /* pre-calculate sin and cos */
2889 sin_angle
=sin(angle
);
2890 cos_angle
=cos(angle
);
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
)
2897 else if(align
==BLEFT
|| align
==BCENTRE
|| align
==BRIGHT
)
2898 hot_y
= -(float)rows_in
/2*style
.magnify
;
2900 hot_y
= -((float)rows_in
/2-(float)font
->descent
)*style
.magnify
;
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
)
2908 hot_x
=(float)max_width
/2*style
.magnify
;
2910 /* reserve space for XPoints */
2911 xp_in
=(XPoint
*)malloc((unsigned)(5*sizeof(XPoint
)));
2915 xp_out
=(XPoint
*)malloc((unsigned)(5*sizeof(XPoint
)));
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
);
2946 /* ***********************************************************************
2947 * Conversion routines for the X resource manager
2948 * ***********************************************************************
2951 #if defined(__STDC__)
2953 Boolean
strtocard( Display
*dsp
,
2962 Boolean
strtocard( dsp
, args
, num_args
, from
, to
, unused
)
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
);
2983 #define done_bert(type, value) \
2985 if (to->addr != NULL) {\
2986 if (to->size < sizeof(type)) {\
2987 to->size = sizeof(type);\
2990 *(type*)(to->addr) = (value);\
2992 static type static_val;\
2993 static_val = (value);\
2994 to->addr = (XtPointer)&static_val;\
2996 to->size = sizeof(type);\
3000 Boolean
cvtStringToStringArray(Display
*display
, XrmValuePtr args
, Cardinal
*num_args
, XrmValuePtr from
, XrmValuePtr to
, XtPointer
*converter_data
)
3003 StringArray a
= NULL
;
3008 XtAppErrorMsg(XtDisplayToApplicationContext(display
),
3009 "cvtStringToStringArray", "wrongParameters",
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);
3018 t
= strchr(s
, delim
);
3020 a
= (StringArray
) XtRealloc((String
) a
, (i
+ 1) * sizeof(*a
));
3023 s
= t
? t
+ 1 : NULL
;
3025 a
= (StringArray
) XtRealloc((String
) a
, (i
+ 1) * sizeof(*a
));
3027 done_bert(StringArray
, a
);
3031 /* ***********************************************************************
3032 * A driver for the above in the flavor of the xt utilities module
3033 * ***********************************************************************
3038 typedef struct tab_data
{
3042 void (*activate_func
)();
3046 #if defined(__STDC__)
3047 static void handle_click( Widget w
, TabData td
, XtPointer call_data
)
3049 static void handle_click(w
, td
, call_data
)
3052 XtPointer call_data
;
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;
3064 /* Change tabs. We must manually inform the UI which tab is current */
3066 XtNlefttabs
, td
->cur
,
3067 XtNrighttabs
, td
->num_tabs
- td
->cur
- 1,
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
,
3084 void (*activate_func
)()
3087 Widget
__vi_CreateTabbedFolder( name
, parent
, tab_labels
, num_tabs
, activate_func
)
3092 void (*activate_func
)();
3096 TabData td
= (TabData
) malloc( sizeof(struct tab_data
) );
3099 XtAppSetTypeConverter( XtDisplayToApplicationContext(XtDisplay(parent
)),
3109 /* init our internal structure */
3111 td
->num_tabs
= num_tabs
;
3112 td
->activate_func
= activate_func
;
3114 /* tabs go on the top */
3115 tabs
= XtVaCreateManagedWidget( "tabs",
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
,
3132 strlen(tab_labels
) + 1,
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",
3147 XmNtopAttachment
, XmATTACH_WIDGET
,
3149 XmNleftAttachment
, XmATTACH_FORM
,
3150 XmNbottomAttachment
, XmATTACH_FORM
,
3151 XmNrightAttachment
, XmATTACH_FORM
,