1 /* ***********************************************************************
2 * This module implements a motif tabbed window widget.
3 * The source is copied from the Free Widget Foundation
4 * This file is divided into thse parts
5 * o - Conversion routines for the X resource manager
6 * o - Routines for drawing rotated text
7 * o - A motif widget for tabbed windows
8 * o - A driver for the above in the flavor of the xt utilities module
9 * ***********************************************************************
18 #include <Xm/RowColumn.h>
19 #include <X11/StringDefs.h>
20 #include <X11/IntrinsicP.h>
22 #include <DECW$INCLUDE/shape.h>
24 #include <X11/extensions/shape.h>
27 #include <X11/Xutil.h>
28 #include <X11/Xatom.h>
32 /* ***********************************************************************
34 * ***********************************************************************
37 /* ************************************************************************ */
40 /* Header file for the `xvertext 5.0' routines.
42 Copyright (c) 1993 Alan Richardson (mppa3@uk.ac.sussex.syma) */
45 /* ************************************************************************ */
47 #ifndef _XVERTEXT_INCLUDED_
48 #define _XVERTEXT_INCLUDED_
51 #define XV_VERSION 5.0
52 #define XV_COPYRIGHT \
53 "xvertext routines Copyright (c) 1993 Alan Richardson"
56 /* ---------------------------------------------------------------------- */
73 /* ---------------------------------------------------------------------- */
75 /* this shoulf be C++ compliant, thanks to
76 vlp@latina.inesc.pt (Vasco Lopes Paulo) */
78 #if defined(__cplusplus) || defined(c_plusplus)
81 static float XRotVersion(char*, int);
82 static void XRotSetMagnification(float);
83 static void XRotSetBoundingBoxPad(int);
84 static int XRotDrawString(Display
*, XFontStruct
*, float,
85 Drawable
, GC
, int, int, char*);
86 static int XRotDrawImageString(Display
*, XFontStruct
*, float,
87 Drawable
, GC
, int, int, char*);
88 static int XRotDrawAlignedString(Display
*, XFontStruct
*, float,
89 Drawable
, GC
, int, int, char*, int);
90 static int XRotDrawAlignedImageString(Display
*, XFontStruct
*, float,
91 Drawable
, GC
, int, int, char*, int);
92 static XPoint
*XRotTextExtents(Display
*, XFontStruct
*, float,
93 int, int, char*, int);
98 static float XRotVersion(char *str
, int n
);
99 static void XRotSetMagnification(float m
);
100 static void XRotSetBoundingBoxPad(int p
);
101 static int XRotDrawString(Display
*dpy
, XFontStruct
*font
, float angle
, Drawable drawable
, GC gc
, int x
, int y
, char *str
);
102 static int XRotDrawImageString(Display
*dpy
, XFontStruct
*font
, float angle
, Drawable drawable
, GC gc
, int x
, int y
, char *str
);
103 static int XRotDrawAlignedString(Display
*dpy
, XFontStruct
*font
, float angle
, Drawable drawable
, GC gc
, int x
, int y
, char *text
, int align
);
104 static int XRotDrawAlignedImageString(Display
*dpy
, XFontStruct
*font
, float angle
, Drawable drawable
, GC gc
, int x
, int y
, char *text
, int align
);
105 static XPoint
*XRotTextExtents(Display
*dpy
, XFontStruct
*font
, float angle
, int x
, int y
, char *text
, int align
);
107 #endif /* __cplusplus */
109 /* ---------------------------------------------------------------------- */
112 #endif /* _XVERTEXT_INCLUDED_ */
117 /* ***********************************************************************
119 * ***********************************************************************
127 The type |StringArray| represents an array of |String|s, with the
128 proviso that by convention the last member of a |StringArray| is
129 always a |NULL| pointer. There is a converter that can construct a
130 |StringArray| from a single string.
133 cvtStringToStringArray
134 ======================
135 The converter from |String| to |StringArray| makes a copy of the
136 passed string and then replaces all occurences of the delimiter
137 with a nul byte. The |StringArray| is filled with pointers to the
140 The delimiter character is the first character in the string.
145 The function |newStringArray| makes a copy of a |StringArray|. It
146 allocates new space for the array itself and for the strings that
152 |freeStringArray| deallocates the array and all strings it
153 contains. Note that this works for StringArrays produced with
154 |newStringArray|, but not for those created by
155 |cvtStringToStringArray|!
160 typedef String
* StringArray
;
162 static Boolean
cvtStringToStringArray(
163 #if NeedFunctionPrototypes
169 XtPointer
*converter_data
174 StringArray
newStringArray(
175 #if NeedFunctionPrototypes
181 void freeStringArray(
182 #if NeedFunctionPrototypes
188 #endif /* _strarray_h_ */
191 /* ***********************************************************************
193 * ***********************************************************************
196 /* Generated by wbuild from "XmTabs.w"
197 ** (generator version Revision: 8.5 of Date: 2001/06/25 15:19:28 )
202 XfwfUpTabs
, XfwfDownTabs
, XfwfLeftTabs
, XfwfRightTabs
,
205 #ifndef XtNorientation
206 #define XtNorientation "orientation"
208 #ifndef XtCOrientation
209 #define XtCOrientation "Orientation"
211 #ifndef XtRTabsOrientation
212 #define XtRTabsOrientation "TabsOrientation"
216 #define XtNlefttabs "lefttabs"
219 #define XtCLefttabs "Lefttabs"
226 #define XtNrighttabs "righttabs"
229 #define XtCRighttabs "Righttabs"
236 #define XtNlabels "labels"
239 #define XtCLabels "Labels"
241 #ifndef XtRStringArray
242 #define XtRStringArray "StringArray"
245 #ifndef XtNtabWidthPercentage
246 #define XtNtabWidthPercentage "tabWidthPercentage"
248 #ifndef XtCTabWidthPercentage
249 #define XtCTabWidthPercentage "TabWidthPercentage"
255 #ifndef XtNcornerwidth
256 #define XtNcornerwidth "cornerwidth"
258 #ifndef XtCCornerwidth
259 #define XtCCornerwidth "Cornerwidth"
262 #define XtRCardinal "Cardinal"
265 #ifndef XtNcornerheight
266 #define XtNcornerheight "cornerheight"
268 #ifndef XtCCornerheight
269 #define XtCCornerheight "Cornerheight"
272 #define XtRCardinal "Cardinal"
275 #ifndef XtNtextmargin
276 #define XtNtextmargin "textmargin"
278 #ifndef XtCTextmargin
279 #define XtCTextmargin "Textmargin"
286 #define XtNtabcolor "tabcolor"
289 #define XtCTabcolor "Tabcolor"
292 #define XtRPixel "Pixel"
296 #define XtNfont "font"
299 #define XtCFont "Font"
301 #ifndef XtRFontStruct
302 #define XtRFontStruct "FontStruct"
305 #ifndef XtNactivateCallback
306 #define XtNactivateCallback "activateCallback"
308 #ifndef XtCActivateCallback
309 #define XtCActivateCallback "ActivateCallback"
312 #define XtRCallback "Callback"
315 typedef struct _XmTabsClassRec
*XmTabsWidgetClass
;
316 typedef struct _XmTabsRec
*XmTabsWidget
;
317 #endif /*_XmTabs_H_*/
320 /* ***********************************************************************
322 * ***********************************************************************
325 /* Generated by wbuild from "XmTabs.w"
326 ** (generator version Revision: 8.5 of Date: 2001/06/25 15:19:28 )
331 /* raz modified 22 Jul 96 for bluestone */
333 #if ! defined(MGR_ShadowThickness)
334 #include <Xm/ManagerP.h>
337 typedef void (*border_highlight_Proc
)(
338 #if NeedFunctionPrototypes
342 #define XtInherit_border_highlight ((border_highlight_Proc) _XtInherit)
343 typedef void (*border_unhighlight_Proc
)(
344 #if NeedFunctionPrototypes
348 #define XtInherit_border_unhighlight ((border_unhighlight_Proc) _XtInherit)
350 /* Constraint resources */
351 /* Private constraint variables */
353 } XmTabsConstraintPart
;
355 typedef struct _XmTabsConstraintRec
{
356 XmManagerConstraintPart xmManager
;
357 XmTabsConstraintPart xmTabs
;
358 } XmTabsConstraintRec
;
363 border_highlight_Proc border_highlight
;
364 border_unhighlight_Proc border_unhighlight
;
365 /* class variables */
368 typedef struct _XmTabsClassRec
{
369 CoreClassPart core_class
;
370 CompositeClassPart composite_class
;
371 ConstraintClassPart constraint_class
;
372 XmManagerClassPart xmManager_class
;
373 XmTabsClassPart xmTabs_class
;
378 TabsOrientation orientation
;
382 int tabWidthPercentage
;
383 Cardinal cornerwidth
;
384 Cardinal cornerheight
;
388 XtCallbackList activateCallback
;
399 typedef struct _XmTabsRec
{
401 CompositePart composite
;
402 ConstraintPart constraint
;
403 XmManagerPart xmManager
;
407 #endif /* _XmTabsP_H_ */
410 /* ***********************************************************************
411 * A motif widget for tabbed windows
412 * ***********************************************************************
415 static void activate(
416 #if NeedFunctionPrototypes
417 Widget
,XEvent
*,String
*,Cardinal
*
421 static XtActionsRec actionsList
[] = {
422 {"activate", activate
},
425 static char defaultTranslations
[] = "\
426 <Btn1Down>,<Btn1Up>: activate() \n\
428 static void _resolve_inheritance(
429 #if NeedFunctionPrototypes
433 static void class_initialize(
434 #if NeedFunctionPrototypes
438 static void initialize(
439 #if NeedFunctionPrototypes
440 Widget
,Widget
,ArgList
,Cardinal
*
443 static Boolean
set_values(
444 #if NeedFunctionPrototypes
445 Widget
,Widget
,Widget
,ArgList
,Cardinal
*
449 #if NeedFunctionPrototypes
450 Widget
,XtValueMask
*,XSetWindowAttributes
*
454 #if NeedFunctionPrototypes
459 #if NeedFunctionPrototypes
460 Widget
,XEvent
*,Region
463 static void border_highlight(
464 #if NeedFunctionPrototypes
468 static void border_unhighlight(
469 #if NeedFunctionPrototypes
474 #if NeedFunctionPrototypes
478 #define min(a, b) ((a )<(b )?(a ):(b ))
481 #define abs(x) ((x )<0 ?-(x ):(x ))
484 static void compute_tabsizes(
485 #if NeedFunctionPrototypes
489 static void comp_hor_tab_shape(
490 #if NeedFunctionPrototypes
491 Widget
,int ,XPoint p
[12],int *,int *,int *
494 static void comp_ver_tab_shape(
495 #if NeedFunctionPrototypes
496 Widget
,int ,XPoint p
[12],int *,int *,int *
499 static void draw_border(
500 #if NeedFunctionPrototypes
501 Widget
,XPoint poly
[12]
504 static void draw_hor_tab(
505 #if NeedFunctionPrototypes
509 static void draw_ver_tab(
510 #if NeedFunctionPrototypes
514 static void create_topgc(
515 #if NeedFunctionPrototypes
519 static void create_bottomgc(
520 #if NeedFunctionPrototypes
524 static void create_textgc(
525 #if NeedFunctionPrototypes
529 static void create_fillgc(
530 #if NeedFunctionPrototypes
534 static void create_backgc(
535 #if NeedFunctionPrototypes
540 #if NeedFunctionPrototypes
541 Widget
,int ,XrmValue
*
544 static void set_shape(
545 #if NeedFunctionPrototypes
549 #define done(type, value) do {\
550 if (to->addr != NULL) {\
551 if (to->size < sizeof(type)) {\
552 to->size = sizeof(type);\
555 *(type*)(to->addr) = (value);\
557 static type static_val;\
558 static_val = (value);\
559 to->addr = (XtPointer)&static_val;\
561 to->size = sizeof(type);\
566 static Boolean
cvtStringToTabsOrientation(
567 #if NeedFunctionPrototypes
568 Display
*,XrmValuePtr
,Cardinal
*,XrmValuePtr
,XrmValuePtr
,XtPointer
*
571 static Boolean
cvtTabsOrientationToString(
572 #if NeedFunctionPrototypes
573 Display
*,XrmValuePtr
,Cardinal
*,XrmValuePtr
,XrmValuePtr
,XtPointer
*
577 #if NeedFunctionPrototypes
578 static void compute_tabsizes(Widget self
)
580 static void compute_tabsizes(self
)Widget self
;
583 int maxwd
, basewidth
, delta
, i
, n
= ((XmTabsWidget
)self
)->xmTabs
.lefttabs
+ ((XmTabsWidget
)self
)->xmTabs
.righttabs
+ 1;
584 int sum
, len
, h
, length
, breadth
, shad
= ((XmTabsWidget
)self
)->xmManager
.shadow_thickness
;
586 if (((XmTabsWidget
)self
)->xmTabs
.offsets
) XtFree((XtPointer
) ((XmTabsWidget
)self
)->xmTabs
.offsets
);
587 if (((XmTabsWidget
)self
)->xmTabs
.tabwidths
) XtFree((XtPointer
) ((XmTabsWidget
)self
)->xmTabs
.tabwidths
);
588 ((XmTabsWidget
)self
)->xmTabs
.offsets
= (XtPointer
) XtMalloc(n
* sizeof(*((XmTabsWidget
)self
)->xmTabs
.offsets
));
589 ((XmTabsWidget
)self
)->xmTabs
.tabwidths
= (XtPointer
) XtMalloc(n
* sizeof(*((XmTabsWidget
)self
)->xmTabs
.tabwidths
));
591 if (((XmTabsWidget
)self
)->xmTabs
.orientation
== XfwfUpTabs
|| ((XmTabsWidget
)self
)->xmTabs
.orientation
== XfwfDownTabs
) {
592 length
= ((XmTabsWidget
)self
)->core
.width
;
593 breadth
= ((XmTabsWidget
)self
)->core
.height
;
595 length
= ((XmTabsWidget
)self
)->core
.height
;
596 breadth
= ((XmTabsWidget
)self
)->core
.width
;
598 if (((XmTabsWidget
)self
)->xmTabs
.tabWidthPercentage
!= 0) { /* Fixed width tabs */
599 basewidth
= ((XmTabsWidget
)self
)->xmTabs
.tabWidthPercentage
* length
/100;
600 if (n
> 1) delta
= (length
- basewidth
)/(((XmTabsWidget
)self
)->xmTabs
.lefttabs
+ ((XmTabsWidget
)self
)->xmTabs
.righttabs
);
601 for (i
= 0; i
< n
; i
++) {
602 ((XmTabsWidget
)self
)->xmTabs
.tabwidths
[i
] = basewidth
;
603 ((XmTabsWidget
)self
)->xmTabs
.offsets
[i
] = i
* delta
;
605 } else if (((XmTabsWidget
)self
)->xmTabs
.labels
== NULL
) { /* Empty tabs */
606 basewidth
= length
/n
;
607 delta
= (length
- basewidth
)/(((XmTabsWidget
)self
)->xmTabs
.lefttabs
+ ((XmTabsWidget
)self
)->xmTabs
.righttabs
);
608 for (i
= 0; i
< n
; i
++) {
609 ((XmTabsWidget
)self
)->xmTabs
.tabwidths
[i
] = basewidth
;
610 ((XmTabsWidget
)self
)->xmTabs
.offsets
[i
] = i
* delta
;
612 } else { /* Variable width tabs */
614 h
= 2 * (((XmTabsWidget
)self
)->xmTabs
.cornerwidth
+ shad
+ ((XmTabsWidget
)self
)->xmTabs
.textmargin
);
615 maxwd
= length
- n
* (shad
+ ((XmTabsWidget
)self
)->xmTabs
.textmargin
);
616 for (i
= 0; i
< n
; i
++) {
617 len
= strlen(((XmTabsWidget
)self
)->xmTabs
.labels
[i
]);
618 ((XmTabsWidget
)self
)->xmTabs
.tabwidths
[i
] = min(maxwd
, XTextWidth(((XmTabsWidget
)self
)->xmTabs
.font
,((XmTabsWidget
)self
)->xmTabs
.labels
[i
],len
) + h
);
619 sum
+= ((XmTabsWidget
)self
)->xmTabs
.tabwidths
[i
];
621 ((XmTabsWidget
)self
)->xmTabs
.offsets
[0] = 0;
623 delta
= (length
- sum
)/(n
- 1); /* Between tabs */
625 delta
= -((sum
- length
+ n
- 2)/(n
- 1)); /* Round down! */
626 for (i
= 1; i
< n
; i
++)
627 ((XmTabsWidget
)self
)->xmTabs
.offsets
[i
] = ((XmTabsWidget
)self
)->xmTabs
.offsets
[i
-1] + ((XmTabsWidget
)self
)->xmTabs
.tabwidths
[i
-1] + delta
;
631 #if NeedFunctionPrototypes
632 static void comp_hor_tab_shape(Widget self
,int i
,XPoint p
[12],int * x0
,int * x1
,int * midy
)
634 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 int shad
= ((XmTabsWidget
)self
)->xmManager
.shadow_thickness
;
638 int k
= min(((XmTabsWidget
)self
)->xmTabs
.cornerheight
, (((XmTabsWidget
)self
)->core
.height
- shad
)/2);
640 * 4 o-------------o 5
646 * 0 o--------o o--------o 9
647 * 11 o---------------------------------------o 10
649 * 11 o---------------------------------------o 10
650 * 0 o--------o o--------o 9
656 * 4 o-------------o 5
659 p
[1].x
= ((XmTabsWidget
)self
)->xmTabs
.offsets
[i
];
660 p
[2].x
= ((XmTabsWidget
)self
)->xmTabs
.offsets
[i
] + ((XmTabsWidget
)self
)->xmTabs
.cornerwidth
;
661 p
[3].x
= ((XmTabsWidget
)self
)->xmTabs
.offsets
[i
] + ((XmTabsWidget
)self
)->xmTabs
.cornerwidth
;
662 p
[4].x
= ((XmTabsWidget
)self
)->xmTabs
.offsets
[i
] + 2 * ((XmTabsWidget
)self
)->xmTabs
.cornerwidth
;
663 p
[5].x
= ((XmTabsWidget
)self
)->xmTabs
.offsets
[i
] + ((XmTabsWidget
)self
)->xmTabs
.tabwidths
[i
] - 2 * ((XmTabsWidget
)self
)->xmTabs
.cornerwidth
;
664 p
[6].x
= ((XmTabsWidget
)self
)->xmTabs
.offsets
[i
] + ((XmTabsWidget
)self
)->xmTabs
.tabwidths
[i
] - ((XmTabsWidget
)self
)->xmTabs
.cornerwidth
;
665 p
[7].x
= ((XmTabsWidget
)self
)->xmTabs
.offsets
[i
] + ((XmTabsWidget
)self
)->xmTabs
.tabwidths
[i
] - ((XmTabsWidget
)self
)->xmTabs
.cornerwidth
;
666 p
[8].x
= ((XmTabsWidget
)self
)->xmTabs
.offsets
[i
] + ((XmTabsWidget
)self
)->xmTabs
.tabwidths
[i
];
667 p
[9].x
= ((XmTabsWidget
)self
)->core
.width
;
668 p
[10].x
= ((XmTabsWidget
)self
)->core
.width
;
671 if (((XmTabsWidget
)self
)->xmTabs
.orientation
== XfwfUpTabs
) {
672 p
[0].y
= ((XmTabsWidget
)self
)->core
.height
- shad
;
673 p
[1].y
= ((XmTabsWidget
)self
)->core
.height
- shad
;
674 p
[2].y
= ((XmTabsWidget
)self
)->core
.height
- shad
- k
;
679 p
[7].y
= ((XmTabsWidget
)self
)->core
.height
- shad
- k
;
680 p
[8].y
= ((XmTabsWidget
)self
)->core
.height
- shad
;
681 p
[9].y
= ((XmTabsWidget
)self
)->core
.height
- shad
;
682 p
[10].y
= ((XmTabsWidget
)self
)->core
.height
;
683 p
[11].y
= ((XmTabsWidget
)self
)->core
.height
;
688 p
[3].y
= ((XmTabsWidget
)self
)->core
.height
- k
;
689 p
[4].y
= ((XmTabsWidget
)self
)->core
.height
;
690 p
[5].y
= ((XmTabsWidget
)self
)->core
.height
;
691 p
[6].y
= ((XmTabsWidget
)self
)->core
.height
- k
;
700 *midy
= (p
[1].y
+ p
[4].y
)/2;
703 #if NeedFunctionPrototypes
704 static void comp_ver_tab_shape(Widget self
,int i
,XPoint p
[12],int * y0
,int * y1
,int * midx
)
706 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 int shad
= ((XmTabsWidget
)self
)->xmManager
.shadow_thickness
;
710 int k
= min(((XmTabsWidget
)self
)->xmTabs
.cornerheight
, (((XmTabsWidget
)self
)->core
.width
- shad
)/2);
728 if (((XmTabsWidget
)self
)->xmTabs
.orientation
== XfwfLeftTabs
) {
729 p
[0].x
= ((XmTabsWidget
)self
)->core
.width
- shad
;
730 p
[1].x
= ((XmTabsWidget
)self
)->core
.width
- shad
;
731 p
[2].x
= ((XmTabsWidget
)self
)->core
.width
- shad
- k
;
736 p
[7].x
= ((XmTabsWidget
)self
)->core
.width
- shad
- k
;
737 p
[8].x
= ((XmTabsWidget
)self
)->core
.width
- shad
;
738 p
[9].x
= ((XmTabsWidget
)self
)->core
.width
- shad
;
739 p
[10].x
= ((XmTabsWidget
)self
)->core
.width
;
740 p
[11].x
= ((XmTabsWidget
)self
)->core
.width
;
745 p
[3].x
= ((XmTabsWidget
)self
)->core
.width
- k
;
746 p
[4].x
= ((XmTabsWidget
)self
)->core
.width
;
747 p
[5].x
= ((XmTabsWidget
)self
)->core
.width
;
748 p
[6].x
= ((XmTabsWidget
)self
)->core
.width
- k
;
756 p
[1].y
= ((XmTabsWidget
)self
)->xmTabs
.offsets
[i
];
757 p
[2].y
= ((XmTabsWidget
)self
)->xmTabs
.offsets
[i
] + ((XmTabsWidget
)self
)->xmTabs
.cornerwidth
;
758 p
[3].y
= ((XmTabsWidget
)self
)->xmTabs
.offsets
[i
] + ((XmTabsWidget
)self
)->xmTabs
.cornerwidth
;
759 p
[4].y
= ((XmTabsWidget
)self
)->xmTabs
.offsets
[i
] + 2 * ((XmTabsWidget
)self
)->xmTabs
.cornerwidth
;
760 p
[5].y
= ((XmTabsWidget
)self
)->xmTabs
.offsets
[i
] + ((XmTabsWidget
)self
)->xmTabs
.tabwidths
[i
] - 2 * ((XmTabsWidget
)self
)->xmTabs
.cornerwidth
;
761 p
[6].y
= ((XmTabsWidget
)self
)->xmTabs
.offsets
[i
] + ((XmTabsWidget
)self
)->xmTabs
.tabwidths
[i
] - ((XmTabsWidget
)self
)->xmTabs
.cornerwidth
;
762 p
[7].y
= ((XmTabsWidget
)self
)->xmTabs
.offsets
[i
] + ((XmTabsWidget
)self
)->xmTabs
.tabwidths
[i
] - ((XmTabsWidget
)self
)->xmTabs
.cornerwidth
;
763 p
[8].y
= ((XmTabsWidget
)self
)->xmTabs
.offsets
[i
] + ((XmTabsWidget
)self
)->xmTabs
.tabwidths
[i
];
764 p
[9].y
= ((XmTabsWidget
)self
)->core
.height
;
765 p
[10].y
= ((XmTabsWidget
)self
)->core
.height
;
769 *midx
= (p
[1].x
+ p
[4].x
)/2;
772 #if NeedFunctionPrototypes
773 static void draw_border(Widget self
,XPoint poly
[12])
775 static void draw_border(self
,poly
)Widget self
;XPoint poly
[12];
778 Display
*dpy
= XtDisplay(self
);
779 Window win
= XtWindow(self
);
781 if (((XmTabsWidget
)self
)->xmTabs
.orientation
== XfwfUpTabs
) {
782 XDrawLines(dpy
, win
, ((XmTabsWidget
)self
)->xmTabs
.topgc
, poly
, 6, CoordModeOrigin
);
783 XDrawLines(dpy
, win
, ((XmTabsWidget
)self
)->xmTabs
.bottomgc
, poly
+ 5, 4, CoordModeOrigin
);
784 XDrawLines(dpy
, win
, ((XmTabsWidget
)self
)->xmTabs
.topgc
, poly
+ 8, 2, CoordModeOrigin
);
786 XDrawLines(dpy
, win
, ((XmTabsWidget
)self
)->xmTabs
.bottomgc
, poly
, 2, CoordModeOrigin
);
787 XDrawLines(dpy
, win
, ((XmTabsWidget
)self
)->xmTabs
.topgc
, poly
+ 1, 4, CoordModeOrigin
);
788 XDrawLines(dpy
, win
, ((XmTabsWidget
)self
)->xmTabs
.bottomgc
, poly
+ 4, 6, CoordModeOrigin
);
792 #if NeedFunctionPrototypes
793 static void draw_hor_tab(Widget self
,Region region
,int i
)
795 static void draw_hor_tab(self
,region
,i
)Widget self
;Region region
;int i
;
799 Display
*dpy
= XtDisplay(self
);
800 Window win
= XtWindow(self
);
804 comp_hor_tab_shape(self
, i
, p
, &x0
, &x1
, &midy
);
805 clip
= XPolygonRegion(p
, XtNumber(p
), WindingRule
);
806 if (region
) XIntersectRegion(clip
, region
, clip
);
807 if (XEmptyRegion(clip
)) return;
809 XSetRegion(dpy
, ((XmTabsWidget
)self
)->xmTabs
.textgc
, clip
);
810 XSetRegion(dpy
, ((XmTabsWidget
)self
)->xmTabs
.topgc
, clip
);
811 XSetRegion(dpy
, ((XmTabsWidget
)self
)->xmTabs
.bottomgc
, clip
);
812 if (i
== ((XmTabsWidget
)self
)->xmTabs
.lefttabs
) {
813 XSetRegion(dpy
, ((XmTabsWidget
)self
)->xmTabs
.backgc
, clip
);
814 XFillPolygon(dpy
, win
, ((XmTabsWidget
)self
)->xmTabs
.backgc
,
815 p
, XtNumber(p
), Convex
, CoordModeOrigin
);
817 XSetRegion(dpy
, ((XmTabsWidget
)self
)->xmTabs
.fillgc
, clip
);
818 XFillPolygon(dpy
, win
, ((XmTabsWidget
)self
)->xmTabs
.fillgc
,
819 p
, XtNumber(p
), Convex
, CoordModeOrigin
);
821 if (((XmTabsWidget
)self
)->xmTabs
.labels
) {
822 int w
, y
, x
, len
= strlen(((XmTabsWidget
)self
)->xmTabs
.labels
[i
]);
823 y
= midy
- (((XmTabsWidget
)self
)->xmTabs
.font
->ascent
+ ((XmTabsWidget
)self
)->xmTabs
.font
->descent
)/2 + ((XmTabsWidget
)self
)->xmTabs
.font
->ascent
;
824 w
= XTextWidth(((XmTabsWidget
)self
)->xmTabs
.font
, ((XmTabsWidget
)self
)->xmTabs
.labels
[i
], len
);
825 if (i
== ((XmTabsWidget
)self
)->xmTabs
.lefttabs
826 || ((XmTabsWidget
)self
)->xmTabs
.tabWidthPercentage
<= 100/(((XmTabsWidget
)self
)->xmTabs
.lefttabs
+ ((XmTabsWidget
)self
)->xmTabs
.righttabs
+ 1))
827 x
= (x0
+ x1
- w
)/2; /* Centered text */
828 else if (i
< ((XmTabsWidget
)self
)->xmTabs
.lefttabs
)
829 x
= x0
+ ((XmTabsWidget
)self
)->xmTabs
.textmargin
; /* Left aligned text */
831 x
= x1
- ((XmTabsWidget
)self
)->xmTabs
.textmargin
- w
; /* Right aligned text */
832 XDrawString(dpy
, win
, ((XmTabsWidget
)self
)->xmTabs
.textgc
, x
, y
, ((XmTabsWidget
)self
)->xmTabs
.labels
[i
], len
);
834 draw_border(self
, p
);
835 XDestroyRegion(clip
);
838 #if NeedFunctionPrototypes
839 static void draw_ver_tab(Widget self
,Region region
,int i
)
841 static void draw_ver_tab(self
,region
,i
)Widget self
;Region region
;int i
;
844 Display
*dpy
= XtDisplay(self
);
845 Window win
= XtWindow(self
);
850 comp_ver_tab_shape(self
, i
, p
, &y0
, &y1
, &midx
);
851 clip
= XPolygonRegion(p
, XtNumber(p
), WindingRule
);
852 if (region
) XIntersectRegion(clip
, region
, clip
);
853 if (XEmptyRegion(clip
)) return;
855 XSetRegion(dpy
, ((XmTabsWidget
)self
)->xmTabs
.textgc
, clip
);
856 XSetRegion(dpy
, ((XmTabsWidget
)self
)->xmTabs
.topgc
, clip
);
857 XSetRegion(dpy
, ((XmTabsWidget
)self
)->xmTabs
.bottomgc
, clip
);
858 if (i
== ((XmTabsWidget
)self
)->xmTabs
.lefttabs
) {
859 XSetRegion(dpy
, ((XmTabsWidget
)self
)->xmTabs
.backgc
, clip
);
860 XFillPolygon(dpy
, win
, ((XmTabsWidget
)self
)->xmTabs
.backgc
,
861 p
, XtNumber(p
), Convex
, CoordModeOrigin
);
863 XSetRegion(dpy
, ((XmTabsWidget
)self
)->xmTabs
.fillgc
, clip
);
864 XFillPolygon(dpy
, win
, ((XmTabsWidget
)self
)->xmTabs
.fillgc
,
865 p
, XtNumber(p
), Convex
, CoordModeOrigin
);
867 if (((XmTabsWidget
)self
)->xmTabs
.labels
) {
869 float angle
= ((XmTabsWidget
)self
)->xmTabs
.orientation
== XfwfLeftTabs
? 90.0 : -90.0;
870 if (i
== ((XmTabsWidget
)self
)->xmTabs
.lefttabs
871 || ((XmTabsWidget
)self
)->xmTabs
.tabWidthPercentage
<= 100/(((XmTabsWidget
)self
)->xmTabs
.lefttabs
+ ((XmTabsWidget
)self
)->xmTabs
.righttabs
+ 1)) {
874 } else if (i
< ((XmTabsWidget
)self
)->xmTabs
.lefttabs
) {
875 y
= y0
+ ((XmTabsWidget
)self
)->xmTabs
.textmargin
;
876 align
= ((XmTabsWidget
)self
)->xmTabs
.orientation
== XfwfLeftTabs
? MRIGHT
: MLEFT
;
878 y
= y1
- ((XmTabsWidget
)self
)->xmTabs
.textmargin
;
879 align
= ((XmTabsWidget
)self
)->xmTabs
.orientation
== XfwfLeftTabs
? MLEFT
: MRIGHT
;
881 XRotDrawAlignedString
882 (dpy
, ((XmTabsWidget
)self
)->xmTabs
.font
, angle
, win
, ((XmTabsWidget
)self
)->xmTabs
.textgc
, midx
, y
, ((XmTabsWidget
)self
)->xmTabs
.labels
[i
], align
);
884 draw_border(self
, p
);
885 XDestroyRegion(clip
);
888 #if NeedFunctionPrototypes
889 static void create_topgc(Widget self
)
891 static void create_topgc(self
)Widget self
;
894 XtGCMask mask
= GCForeground
| GCLineWidth
;
897 if (((XmTabsWidget
)self
)->xmTabs
.topgc
!= NULL
) XFreeGC(XtDisplay(self
), ((XmTabsWidget
)self
)->xmTabs
.topgc
);
898 values
.foreground
= ((XmTabsWidget
)self
)->xmManager
.top_shadow_color
;
899 values
.line_width
= 2 * ((XmTabsWidget
)self
)->xmManager
.shadow_thickness
;
900 ((XmTabsWidget
)self
)->xmTabs
.topgc
= XCreateGC(XtDisplay(self
), RootWindowOfScreen(XtScreen(self
)),
904 #if NeedFunctionPrototypes
905 static void create_bottomgc(Widget self
)
907 static void create_bottomgc(self
)Widget self
;
910 XtGCMask mask
= GCForeground
| GCLineWidth
;
913 if (((XmTabsWidget
)self
)->xmTabs
.bottomgc
!= NULL
) XFreeGC(XtDisplay(self
), ((XmTabsWidget
)self
)->xmTabs
.bottomgc
);
914 values
.foreground
= ((XmTabsWidget
)self
)->xmManager
.bottom_shadow_color
;
915 values
.line_width
= 2 * ((XmTabsWidget
)self
)->xmManager
.shadow_thickness
;
916 ((XmTabsWidget
)self
)->xmTabs
.bottomgc
= XCreateGC(XtDisplay(self
), RootWindowOfScreen(XtScreen(self
)),
920 #if NeedFunctionPrototypes
921 static void create_textgc(Widget self
)
923 static void create_textgc(self
)Widget self
;
926 XtGCMask mask
= GCForeground
| GCFont
;
929 if (((XmTabsWidget
)self
)->xmTabs
.textgc
!= NULL
) XFreeGC(XtDisplay(self
), ((XmTabsWidget
)self
)->xmTabs
.textgc
);
930 values
.foreground
= ((XmTabsWidget
)self
)->xmManager
.foreground
;
931 values
.font
= ((XmTabsWidget
)self
)->xmTabs
.font
->fid
;
932 ((XmTabsWidget
)self
)->xmTabs
.textgc
= XCreateGC(XtDisplay(self
), RootWindowOfScreen(XtScreen(self
)),
936 #if NeedFunctionPrototypes
937 static void create_fillgc(Widget self
)
939 static void create_fillgc(self
)Widget self
;
942 XtGCMask mask
= GCForeground
;
945 if (((XmTabsWidget
)self
)->xmTabs
.fillgc
!= NULL
) XFreeGC(XtDisplay(self
), ((XmTabsWidget
)self
)->xmTabs
.fillgc
);
946 values
.foreground
= ((XmTabsWidget
)self
)->xmTabs
.tabcolor
;
947 ((XmTabsWidget
)self
)->xmTabs
.fillgc
= XCreateGC(XtDisplay(self
), RootWindowOfScreen(XtScreen(self
)),
951 #if NeedFunctionPrototypes
952 static void create_backgc(Widget self
)
954 static void create_backgc(self
)Widget self
;
957 XtGCMask mask
= GCForeground
;
960 if (((XmTabsWidget
)self
)->xmTabs
.backgc
!= NULL
) XFreeGC(XtDisplay(self
), ((XmTabsWidget
)self
)->xmTabs
.backgc
);
961 values
.foreground
= ((XmTabsWidget
)self
)->core
.background_pixel
;
962 ((XmTabsWidget
)self
)->xmTabs
.backgc
= XCreateGC(XtDisplay(self
), RootWindowOfScreen(XtScreen(self
)),
966 #if NeedFunctionPrototypes
967 static void copy_bg(Widget self
,int offset
,XrmValue
* value
)
969 static void copy_bg(self
,offset
,value
)Widget self
;int offset
;XrmValue
* value
;
972 value
->addr
= (XtPointer
) &((XmTabsWidget
)self
)->core
.background_pixel
;
975 #if NeedFunctionPrototypes
976 static void set_shape(Widget self
)
978 static void set_shape(self
)Widget self
;
981 int x0
, x1
, midy
, y0
, y1
, midx
, i
;
985 if (! XtIsRealized(self
)) return;
987 region
= XCreateRegion();
989 switch (((XmTabsWidget
)self
)->xmTabs
.orientation
) {
992 for (i
= 0; i
<= ((XmTabsWidget
)self
)->xmTabs
.lefttabs
+ ((XmTabsWidget
)self
)->xmTabs
.righttabs
; i
++) {
993 comp_hor_tab_shape(self
, i
, poly
, &x0
, &x1
, &midy
);
994 clip
= XPolygonRegion(poly
, XtNumber(poly
), WindingRule
);
995 XUnionRegion(region
, clip
, region
);
996 XDestroyRegion(clip
);
1001 for (i
= 0; i
<= ((XmTabsWidget
)self
)->xmTabs
.lefttabs
+ ((XmTabsWidget
)self
)->xmTabs
.righttabs
; i
++) {
1002 comp_ver_tab_shape(self
, i
, poly
, &y0
, &y1
, &midx
);
1003 clip
= XPolygonRegion(poly
, XtNumber(poly
), WindingRule
);
1004 XUnionRegion(region
, clip
, region
);
1005 XDestroyRegion(clip
);
1009 XShapeCombineRegion(XtDisplay(self
), XtWindow(self
), ShapeBounding
,
1010 0, 0, region
, ShapeSet
);
1011 XDestroyRegion(region
);
1015 #if NeedFunctionPrototypes
1016 static Boolean
cvtStringToTabsOrientation(Display
* display
,XrmValuePtr args
,Cardinal
* num_args
,XrmValuePtr from
,XrmValuePtr to
,XtPointer
* converter_data
)
1018 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 TabsOrientation a
= XfwfUpTabs
;
1022 char *s
= (char*) from
->addr
;
1025 TabsOrientation orient
;
1027 { "up", XfwfUpTabs
},
1028 { "uptabs", XfwfUpTabs
},
1029 { "down", XfwfDownTabs
},
1030 { "downtabs", XfwfDownTabs
},
1031 { "left", XfwfLeftTabs
},
1032 { "lefttabs", XfwfLeftTabs
},
1033 { "right", XfwfRightTabs
},
1034 { "righttabs", XfwfRightTabs
},
1040 (XtDisplayToApplicationContext(display
),
1041 "cvtStringToTabsOrientation", "wrongParameters", "XtToolkitError",
1042 "String to TabsOrientation conversion needs no arguments",
1043 (String
*) NULL
, (Cardinal
*) NULL
);
1045 for (i
=0; i
<XtNumber(strings
); i
++)
1046 if ( strcmp( s
, strings
[i
].name
) == 0 ) {
1047 a
|= strings
[i
].orient
;
1051 if ( i
>= XtNumber(strings
) )
1052 XtDisplayStringConversionWarning(display
, s
, "TabsOrientation");
1053 done(TabsOrientation
, a
);
1056 #if NeedFunctionPrototypes
1057 static Boolean
cvtTabsOrientationToString(Display
* display
,XrmValuePtr args
,Cardinal
* num_args
,XrmValuePtr from
,XrmValuePtr to
,XtPointer
* converter_data
)
1059 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 TabsOrientation
*a
= (TabsOrientation
*) from
->addr
;
1066 (XtDisplayToApplicationContext(display
),
1067 "cvtTabsOrientationToString", "wrongParameters", "XtToolkitError",
1068 "TabsOrientation to String conversion needs no arguments",
1069 (String
*) NULL
, (Cardinal
*) NULL
);
1071 case XfwfUpTabs
: done(String
, "up");
1072 case XfwfDownTabs
: done(String
, "down");
1073 case XfwfLeftTabs
: done(String
, "left");
1074 case XfwfRightTabs
: done(String
, "right");
1077 (XtDisplayToApplicationContext(display
),
1078 "cvtTabsOrientationToString", "illParameters", "XtToolkitError",
1079 "TabsOrientation to String conversion got illegal argument",
1080 (String
*) NULL
, (Cardinal
*) NULL
);
1084 static XtResource resources
[] = {
1085 {XtNorientation
,XtCOrientation
,XtRTabsOrientation
,sizeof(((XmTabsRec
*)NULL
)->xmTabs
.orientation
),XtOffsetOf(XmTabsRec
,xmTabs
.orientation
),XtRImmediate
,(XtPointer
)XfwfUpTabs
},
1086 {XtNlefttabs
,XtCLefttabs
,XtRInt
,sizeof(((XmTabsRec
*)NULL
)->xmTabs
.lefttabs
),XtOffsetOf(XmTabsRec
,xmTabs
.lefttabs
),XtRImmediate
,(XtPointer
)0 },
1087 {XtNrighttabs
,XtCRighttabs
,XtRInt
,sizeof(((XmTabsRec
*)NULL
)->xmTabs
.righttabs
),XtOffsetOf(XmTabsRec
,xmTabs
.righttabs
),XtRImmediate
,(XtPointer
)0 },
1088 {XtNlabels
,XtCLabels
,XtRStringArray
,sizeof(((XmTabsRec
*)NULL
)->xmTabs
.labels
),XtOffsetOf(XmTabsRec
,xmTabs
.labels
),XtRImmediate
,(XtPointer
)NULL
},
1089 {XtNtabWidthPercentage
,XtCTabWidthPercentage
,XtRInt
,sizeof(((XmTabsRec
*)NULL
)->xmTabs
.tabWidthPercentage
),XtOffsetOf(XmTabsRec
,xmTabs
.tabWidthPercentage
),XtRImmediate
,(XtPointer
)50 },
1090 {XtNcornerwidth
,XtCCornerwidth
,XtRCardinal
,sizeof(((XmTabsRec
*)NULL
)->xmTabs
.cornerwidth
),XtOffsetOf(XmTabsRec
,xmTabs
.cornerwidth
),XtRImmediate
,(XtPointer
)3 },
1091 {XtNcornerheight
,XtCCornerheight
,XtRCardinal
,sizeof(((XmTabsRec
*)NULL
)->xmTabs
.cornerheight
),XtOffsetOf(XmTabsRec
,xmTabs
.cornerheight
),XtRImmediate
,(XtPointer
)3 },
1092 {XtNtextmargin
,XtCTextmargin
,XtRInt
,sizeof(((XmTabsRec
*)NULL
)->xmTabs
.textmargin
),XtOffsetOf(XmTabsRec
,xmTabs
.textmargin
),XtRImmediate
,(XtPointer
)3 },
1093 {XtNtabcolor
,XtCTabcolor
,XtRPixel
,sizeof(((XmTabsRec
*)NULL
)->xmTabs
.tabcolor
),XtOffsetOf(XmTabsRec
,xmTabs
.tabcolor
),XtRCallProc
,(XtPointer
)copy_bg
},
1094 {XtNfont
,XtCFont
,XtRFontStruct
,sizeof(((XmTabsRec
*)NULL
)->xmTabs
.font
),XtOffsetOf(XmTabsRec
,xmTabs
.font
),XtRString
,(XtPointer
)XtDefaultFont
},
1095 {XtNactivateCallback
,XtCActivateCallback
,XtRCallback
,sizeof(((XmTabsRec
*)NULL
)->xmTabs
.activateCallback
),XtOffsetOf(XmTabsRec
,xmTabs
.activateCallback
),XtRImmediate
,(XtPointer
)NULL
},
1098 XmTabsClassRec xmTabsClassRec
= {
1099 { /* core_class part */
1100 /* superclass */ (WidgetClass
) &xmManagerClassRec
,
1101 /* class_name */ "XmTabs",
1102 /* widget_size */ sizeof(XmTabsRec
),
1103 /* class_initialize */ class_initialize
,
1104 /* class_part_initialize*/ _resolve_inheritance
,
1105 /* class_inited */ FALSE
,
1106 /* initialize */ initialize
,
1107 /* initialize_hook */ NULL
,
1108 /* realize */ realize
,
1109 /* actions */ actionsList
,
1110 /* num_actions */ 1,
1111 /* resources */ resources
,
1112 /* num_resources */ 11,
1113 /* xrm_class */ NULLQUARK
,
1114 /* compres_motion */ True
,
1115 /* compress_exposure */ XtExposeCompressMultiple
,
1116 /* compress_enterleave */ True
,
1117 /* visible_interest */ False
,
1118 /* destroy */ destroy
,
1119 /* resize */ resize
,
1120 /* expose */ expose
,
1121 /* set_values */ set_values
,
1122 /* set_values_hook */ NULL
,
1123 /* set_values_almost */ XtInheritSetValuesAlmost
,
1124 /* get_values+hook */ NULL
,
1125 /* accept_focus */ XtInheritAcceptFocus
,
1126 /* version */ XtVersion
,
1127 /* callback_private */ NULL
,
1128 /* tm_table */ defaultTranslations
,
1129 /* query_geometry */ XtInheritQueryGeometry
,
1130 /* display_acceleator */ XtInheritDisplayAccelerator
,
1131 /* extension */ NULL
1133 { /* composite_class part */
1134 XtInheritGeometryManager
,
1135 XtInheritChangeManaged
,
1136 XtInheritInsertChild
,
1137 XtInheritDeleteChild
,
1140 { /* constraint_class part */
1141 /* constraint_resources */ NULL
,
1142 /* num_constraint_resources */ 0,
1143 /* constraint_size */ sizeof(XmTabsConstraintRec
),
1144 /* constraint_initialize */ NULL
,
1145 /* constraint_destroy */ NULL
,
1146 /* constraint_set_values */ NULL
,
1147 /* constraint_extension */ NULL
1149 { /* XmManager class part */
1150 #define manager_extension extension
1151 /* translations */ XtInheritTranslations
,
1152 /* syn_resources */ NULL
,
1153 /* num_syn_resources */ 0 ,
1154 /* syn_constraint_resources */ NULL
,
1155 /* num_syn_constraint_resources */ 0 ,
1156 /* parent_process */ XmInheritParentProcess
,
1157 /* manager_extension */ NULL
,
1159 { /* XmTabs_class part */
1164 WidgetClass xmTabsWidgetClass
= (WidgetClass
) &xmTabsClassRec
;
1166 static void activate(Widget self
, XEvent
*event
, String
*params
, Cardinal
*num_params
)
1168 int x0
, x1
, dummy
, i
, x
, y
;
1171 switch (((XmTabsWidget
)self
)->xmTabs
.orientation
) {
1174 x
= event
->xbutton
.x
;
1175 comp_hor_tab_shape(self
, ((XmTabsWidget
)self
)->xmTabs
.lefttabs
, poly
, &x0
, &x1
, &dummy
);
1176 if (x0
<= x
&& x
< x1
) {
1177 XtCallCallbackList(self
, ((XmTabsWidget
)self
)->xmTabs
.activateCallback
, (XtPointer
) 0);
1180 for (i
= -1; i
>= -((XmTabsWidget
)self
)->xmTabs
.lefttabs
; i
--) {
1181 comp_hor_tab_shape(self
, i
+ ((XmTabsWidget
)self
)->xmTabs
.lefttabs
, poly
, &x0
, &x1
, &dummy
);
1182 if (x0
<= x
&& x
< x1
) {
1183 XtCallCallbackList(self
, ((XmTabsWidget
)self
)->xmTabs
.activateCallback
, (XtPointer
) i
);
1187 for (i
= 1; i
<= ((XmTabsWidget
)self
)->xmTabs
.righttabs
; i
++) {
1188 comp_hor_tab_shape(self
, i
+ ((XmTabsWidget
)self
)->xmTabs
.lefttabs
, poly
, &x0
, &x1
, &dummy
);
1189 if (x0
<= x
&& x
< x1
) {
1190 XtCallCallbackList(self
, ((XmTabsWidget
)self
)->xmTabs
.activateCallback
, (XtPointer
) i
);
1197 y
= event
->xbutton
.y
;
1198 comp_ver_tab_shape(self
, ((XmTabsWidget
)self
)->xmTabs
.lefttabs
, poly
, &x0
, &x1
, &dummy
);
1199 if (x0
<= y
&& y
< x1
) {
1200 XtCallCallbackList(self
, ((XmTabsWidget
)self
)->xmTabs
.activateCallback
, (XtPointer
) 0);
1203 for (i
= -1; i
>= -((XmTabsWidget
)self
)->xmTabs
.lefttabs
; i
--) {
1204 comp_ver_tab_shape(self
, i
+ ((XmTabsWidget
)self
)->xmTabs
.lefttabs
, poly
, &x0
, &x1
, &dummy
);
1205 if (x0
<= y
&& y
< x1
) {
1206 XtCallCallbackList(self
, ((XmTabsWidget
)self
)->xmTabs
.activateCallback
, (XtPointer
) i
);
1210 for (i
= 1; i
<= ((XmTabsWidget
)self
)->xmTabs
.righttabs
; i
++) {
1211 comp_ver_tab_shape(self
, i
+ ((XmTabsWidget
)self
)->xmTabs
.lefttabs
, poly
, &x0
, &x1
, &dummy
);
1212 if (x0
<= y
&& y
< x1
) {
1213 XtCallCallbackList(self
, ((XmTabsWidget
)self
)->xmTabs
.activateCallback
, (XtPointer
) i
);
1221 static void _resolve_inheritance(WidgetClass
class)
1223 XmTabsWidgetClass c
= (XmTabsWidgetClass
) class;
1224 XmTabsWidgetClass super
;
1225 static CompositeClassExtensionRec extension_rec
= {
1226 NULL
, NULLQUARK
, XtCompositeExtensionVersion
,
1227 sizeof(CompositeClassExtensionRec
), True
};
1228 CompositeClassExtensionRec
*ext
;
1229 ext
= (XtPointer
)XtMalloc(sizeof(*ext
));
1230 *ext
= extension_rec
;
1231 ext
->next_extension
= c
->composite_class
.extension
;
1232 c
->composite_class
.extension
= ext
;
1233 if (class == xmTabsWidgetClass
) return;
1234 super
= (XmTabsWidgetClass
)class->core_class
.superclass
;
1235 if (c
->xmTabs_class
.border_highlight
== XtInherit_border_highlight
)
1236 c
->xmTabs_class
.border_highlight
= super
->xmTabs_class
.border_highlight
;
1237 if (c
->xmTabs_class
.border_unhighlight
== XtInherit_border_unhighlight
)
1238 c
->xmTabs_class
.border_unhighlight
= super
->xmTabs_class
.border_unhighlight
;
1241 #if NeedFunctionPrototypes
1242 static void class_initialize(void)
1244 static void class_initialize(void)
1247 XtSetTypeConverter(XtRString
, "StringArray",
1248 cvtStringToStringArray
,
1249 NULL
, 0, XtCacheNone
, NULL
);
1250 XtSetTypeConverter(XtRString
, "TabsOrientation",
1251 cvtStringToTabsOrientation
,
1252 NULL
, 0, XtCacheNone
, NULL
);
1253 XtSetTypeConverter("TabsOrientation", XtRString
,
1254 cvtTabsOrientationToString
,
1255 NULL
, 0, XtCacheNone
, NULL
);
1258 #if NeedFunctionPrototypes
1259 static void initialize(Widget request
,Widget self
,ArgList args
,Cardinal
* num_args
)
1261 static void initialize(request
,self
,args
,num_args
)Widget request
;Widget self
;ArgList args
;Cardinal
* num_args
;
1267 ((XmTabsWidget
)self
)->xmManager
.traversal_on
= FALSE
;
1268 ((XmTabsWidget
)self
)->xmTabs
.topgc
= NULL
;
1270 ((XmTabsWidget
)self
)->xmTabs
.bottomgc
= NULL
;
1271 create_bottomgc(self
);
1272 ((XmTabsWidget
)self
)->xmTabs
.textgc
= NULL
;
1273 create_textgc(self
);
1274 ((XmTabsWidget
)self
)->xmTabs
.fillgc
= NULL
;
1275 create_fillgc(self
);
1276 ((XmTabsWidget
)self
)->xmTabs
.backgc
= NULL
;
1277 create_backgc(self
);
1278 if (((XmTabsWidget
)self
)->xmTabs
.labels
) {
1279 h
= (String
*) XtMalloc((((XmTabsWidget
)self
)->xmTabs
.lefttabs
+ ((XmTabsWidget
)self
)->xmTabs
.righttabs
+ 1) * sizeof(*h
));
1280 for (i
= ((XmTabsWidget
)self
)->xmTabs
.lefttabs
+ ((XmTabsWidget
)self
)->xmTabs
.righttabs
; i
>= 0; i
--)
1281 h
[i
] = XtNewString(((XmTabsWidget
)self
)->xmTabs
.labels
[i
]);
1282 ((XmTabsWidget
)self
)->xmTabs
.labels
= h
;
1284 if (((XmTabsWidget
)self
)->xmTabs
.tabWidthPercentage
< 0 || ((XmTabsWidget
)self
)->xmTabs
.tabWidthPercentage
> 100) {
1285 XtAppWarning(XtWidgetToApplicationContext(self
),
1286 "tabWidthPercentage out of range; reset to 50");
1287 ((XmTabsWidget
)self
)->xmTabs
.tabWidthPercentage
= 50;
1289 ((XmTabsWidget
)self
)->xmTabs
.offsets
= NULL
;
1290 ((XmTabsWidget
)self
)->xmTabs
.tabwidths
= NULL
;
1291 compute_tabsizes(self
);
1294 #if NeedFunctionPrototypes
1295 static Boolean
set_values(Widget old
,Widget request
,Widget self
,ArgList args
,Cardinal
* num_args
)
1297 static Boolean
set_values(old
,request
,self
,args
,num_args
)Widget old
;Widget request
;Widget self
;ArgList args
;Cardinal
* num_args
;
1300 Bool redraw
= FALSE
, resize_labels
= FALSE
;
1304 if (((XmTabsWidget
)self
)->core
.background_pixel
!= ((XmTabsWidget
)old
)->core
.background_pixel
1305 || ((XmTabsWidget
)self
)->core
.background_pixmap
!= ((XmTabsWidget
)old
)->core
.background_pixmap
1306 || ((XmTabsWidget
)self
)->xmManager
.shadow_thickness
!= ((XmTabsWidget
)old
)->xmManager
.shadow_thickness
) {
1308 create_bottomgc(self
);
1309 create_backgc(self
);
1311 if (((XmTabsWidget
)self
)->xmManager
.foreground
!= ((XmTabsWidget
)old
)->xmManager
.foreground
|| ((XmTabsWidget
)self
)->xmTabs
.font
!= ((XmTabsWidget
)old
)->xmTabs
.font
) {
1312 create_textgc(self
);
1315 if (((XmTabsWidget
)self
)->xmTabs
.tabcolor
!= ((XmTabsWidget
)old
)->xmTabs
.tabcolor
) {
1316 create_fillgc(self
);
1319 if ((((XmTabsWidget
)self
)->xmTabs
.textmargin
!= ((XmTabsWidget
)old
)->xmTabs
.textmargin
&& ((XmTabsWidget
)self
)->xmTabs
.tabWidthPercentage
== 0)
1320 || ((XmTabsWidget
)self
)->xmTabs
.cornerwidth
!= ((XmTabsWidget
)old
)->xmTabs
.cornerwidth
1321 || ((XmTabsWidget
)self
)->xmTabs
.cornerheight
!= ((XmTabsWidget
)old
)->xmTabs
.cornerheight
) {
1322 resize_labels
= TRUE
;
1324 if (((XmTabsWidget
)self
)->xmTabs
.labels
!= ((XmTabsWidget
)old
)->xmTabs
.labels
) {
1325 if (((XmTabsWidget
)self
)->xmTabs
.labels
) {
1326 h
= (String
*) XtMalloc((((XmTabsWidget
)self
)->xmTabs
.lefttabs
+ ((XmTabsWidget
)self
)->xmTabs
.righttabs
+ 1) * sizeof(*h
));
1327 for (i
= ((XmTabsWidget
)self
)->xmTabs
.lefttabs
+ ((XmTabsWidget
)self
)->xmTabs
.righttabs
; i
>= 0; i
--)
1328 h
[i
] = XtNewString(((XmTabsWidget
)self
)->xmTabs
.labels
[i
]);
1329 ((XmTabsWidget
)self
)->xmTabs
.labels
= h
;
1331 if (((XmTabsWidget
)old
)->xmTabs
.labels
) {
1332 for (i
= ((XmTabsWidget
)old
)->xmTabs
.lefttabs
+ ((XmTabsWidget
)old
)->xmTabs
.righttabs
; i
>= 0; i
--)
1333 XtFree(((XmTabsWidget
)old
)->xmTabs
.labels
[i
]);
1334 XtFree((XtPointer
) ((XmTabsWidget
)old
)->xmTabs
.labels
);
1336 resize_labels
= TRUE
;
1338 if (((XmTabsWidget
)self
)->xmTabs
.tabWidthPercentage
< 0 || ((XmTabsWidget
)self
)->xmTabs
.tabWidthPercentage
> 100) {
1339 XtAppWarning(XtWidgetToApplicationContext(self
),
1340 "tabWidthPercentage out of range; reset to 50");
1341 ((XmTabsWidget
)self
)->xmTabs
.tabWidthPercentage
= 50;
1343 if (((XmTabsWidget
)old
)->xmTabs
.tabWidthPercentage
!= ((XmTabsWidget
)self
)->xmTabs
.tabWidthPercentage
)
1344 resize_labels
= TRUE
;
1345 if (((XmTabsWidget
)self
)->xmTabs
.lefttabs
!= ((XmTabsWidget
)old
)->xmTabs
.lefttabs
|| ((XmTabsWidget
)self
)->xmTabs
.righttabs
!= ((XmTabsWidget
)old
)->xmTabs
.righttabs
)
1347 if (resize_labels
) {
1348 compute_tabsizes(self
);
1354 #if NeedFunctionPrototypes
1355 static void realize(Widget self
,XtValueMask
* mask
,XSetWindowAttributes
* attributes
)
1357 static void realize(self
,mask
,attributes
)Widget self
;XtValueMask
* mask
;XSetWindowAttributes
* attributes
;
1360 *mask
|= CWBitGravity
;
1361 attributes
->bit_gravity
= ForgetGravity
;
1362 xmManagerClassRec
.core_class
.realize(self
, mask
, attributes
);
1366 #if NeedFunctionPrototypes
1367 static void resize(Widget self
)
1369 static void resize(self
)Widget self
;
1372 if (XtIsRealized(self
))
1373 XClearArea(XtDisplay(self
), XtWindow(self
), 0, 0, 0, 0, True
);
1374 compute_tabsizes(self
);
1376 if ( xmManagerClassRec
.core_class
.resize
) xmManagerClassRec
.core_class
.resize(self
);
1379 #if NeedFunctionPrototypes
1380 static void expose(Widget self
,XEvent
* event
,Region region
)
1382 static void expose(self
,event
,region
)Widget self
;XEvent
* event
;Region region
;
1387 if (! XtIsRealized(self
)) return;
1389 switch (((XmTabsWidget
)self
)->xmTabs
.orientation
) {
1392 for (i
= 0; i
< ((XmTabsWidget
)self
)->xmTabs
.lefttabs
; i
++)
1393 draw_hor_tab(self
, region
, i
);
1394 for (i
= ((XmTabsWidget
)self
)->xmTabs
.lefttabs
+ ((XmTabsWidget
)self
)->xmTabs
.righttabs
; i
> ((XmTabsWidget
)self
)->xmTabs
.lefttabs
; i
--)
1395 draw_hor_tab(self
, region
, i
);
1396 draw_hor_tab(self
, region
, ((XmTabsWidget
)self
)->xmTabs
.lefttabs
);
1400 for (i
= 0; i
< ((XmTabsWidget
)self
)->xmTabs
.lefttabs
; i
++)
1401 draw_ver_tab(self
, region
, i
);
1402 for (i
= ((XmTabsWidget
)self
)->xmTabs
.lefttabs
+ ((XmTabsWidget
)self
)->xmTabs
.righttabs
; i
> ((XmTabsWidget
)self
)->xmTabs
.lefttabs
; i
--)
1403 draw_ver_tab(self
, region
, i
);
1404 draw_ver_tab(self
, region
, ((XmTabsWidget
)self
)->xmTabs
.lefttabs
);
1407 /* Focus highlight? */
1410 #if NeedFunctionPrototypes
1411 static void border_highlight(void)
1413 static void border_highlight(void)
1418 #if NeedFunctionPrototypes
1419 static void border_unhighlight(void)
1421 static void border_unhighlight(void)
1426 #if NeedFunctionPrototypes
1427 static void destroy(Widget self
)
1429 static void destroy(self
)Widget self
;
1434 if (((XmTabsWidget
)self
)->xmTabs
.labels
) {
1435 for (i
= ((XmTabsWidget
)self
)->xmTabs
.lefttabs
+ ((XmTabsWidget
)self
)->xmTabs
.righttabs
; i
>= 0; i
--)
1436 XtFree(((XmTabsWidget
)self
)->xmTabs
.labels
[i
]);
1437 XtFree((XtPointer
) ((XmTabsWidget
)self
)->xmTabs
.labels
);
1439 if (((XmTabsWidget
)self
)->xmTabs
.offsets
)
1440 XtFree((XtPointer
) ((XmTabsWidget
)self
)->xmTabs
.offsets
);
1441 if (((XmTabsWidget
)self
)->xmTabs
.tabwidths
)
1442 XtFree((XtPointer
) ((XmTabsWidget
)self
)->xmTabs
.tabwidths
);
1446 /* ***********************************************************************
1447 * Routines for drawing rotated text
1448 * ***********************************************************************
1451 /* xvertext 5.0, Copyright (c) 1993 Alan Richardson (mppa3@uk.ac.sussex.syma)
1453 * Permission to use, copy, modify, and distribute this software and its
1454 * documentation for any purpose and without fee is hereby granted, provided
1455 * that the above copyright notice appear in all copies and that both the
1456 * copyright notice and this permission notice appear in supporting
1457 * documentation. All work developed as a consequence of the use of
1458 * this program should duly acknowledge such use. No representations are
1459 * made about the suitability of this software for any purpose. It is
1460 * provided "as is" without express or implied warranty.
1462 * 8 Jun '95: [Bert Bos] added GCClipXOrigin|GCClipYOrigin|GCClipMask
1463 * when calling XCopyGC()
1466 /* ********************************************************************** */
1469 /* BETTER: xvertext now does rotation at any angle!!
1471 * BEWARE: function arguments have CHANGED since version 2.0!!
1474 /* ********************************************************************** */
1478 /* ---------------------------------------------------------------------- */
1481 /* Make sure cache size is set */
1483 #ifndef CACHE_SIZE_LIMIT
1484 #define CACHE_SIZE_LIMIT 0
1485 #endif /*CACHE_SIZE_LIMIT */
1487 /* Make sure a cache method is specified */
1489 #ifndef CACHE_XIMAGES
1490 #ifndef CACHE_BITMAPS
1491 #define CACHE_BITMAPS
1492 #endif /*CACHE_BITMAPS*/
1493 #endif /*CACHE_XIMAGES*/
1496 /* ---------------------------------------------------------------------- */
1499 /* Debugging macros */
1507 #define DEBUG_PRINT1(a) if (debug) printf (a)
1508 #define DEBUG_PRINT2(a, b) if (debug) printf (a, b)
1509 #define DEBUG_PRINT3(a, b, c) if (debug) printf (a, b, c)
1510 #define DEBUG_PRINT4(a, b, c, d) if (debug) printf (a, b, c, d)
1511 #define DEBUG_PRINT5(a, b, c, d, e) if (debug) printf (a, b, c, d, e)
1514 /* ---------------------------------------------------------------------- */
1518 #define M_PI 3.14159265358979323846
1522 /* ---------------------------------------------------------------------- */
1525 /* A structure holding everything needed for a rotated string */
1527 typedef struct rotated_text_item_template
{
1551 struct rotated_text_item_template
*next
;
1554 RotatedTextItem
*first_text_item
=NULL
;
1557 /* ---------------------------------------------------------------------- */
1560 /* A structure holding current magnification and bounding box padding */
1562 static struct style_template
{
1571 /* ---------------------------------------------------------------------- */
1574 static char *my_strdup(char *str
);
1575 static char *my_strtok(char *str1
, char *str2
);
1577 static float XRotVersion(char *str
, int n
);
1578 static void XRotSetMagnification(float m
);
1579 static void XRotSetBoundingBoxPad(int p
);
1580 static int XRotDrawString(Display
*dpy
, XFontStruct
*font
, float angle
, Drawable drawable
, GC gc
, int x
, int y
, char *str
);
1581 static int XRotDrawImageString(Display
*dpy
, XFontStruct
*font
, float angle
, Drawable drawable
, GC gc
, int x
, int y
, char *str
);
1582 static int XRotDrawAlignedString(Display
*dpy
, XFontStruct
*font
, float angle
, Drawable drawable
, GC gc
, int x
, int y
, char *text
, int align
);
1583 static int XRotDrawAlignedImageString(Display
*dpy
, XFontStruct
*font
, float angle
, Drawable drawable
, GC gc
, int x
, int y
, char *text
, int align
);
1584 static XPoint
*XRotTextExtents(Display
*dpy
, XFontStruct
*font
, float angle
, int x
, int y
, char *text
, int align
);
1586 static XImage
*MakeXImage(Display
*dpy
, int w
, int h
);
1587 static int XRotPaintAlignedString(Display
*dpy
, XFontStruct
*font
, float angle
, Drawable drawable
, GC gc
, int x
, int y
, char *text
, int align
, int bg
);
1588 static int XRotDrawHorizontalString(Display
*dpy
, XFontStruct
*font
, Drawable drawable
, GC gc
, int x
, int y
, char *text
, int align
, int bg
);
1589 static RotatedTextItem
*XRotRetrieveFromCache(Display
*dpy
, XFontStruct
*font
, float angle
, char *text
, int align
);
1590 static RotatedTextItem
*XRotCreateTextItem(Display
*dpy
, XFontStruct
*font
, float angle
, char *text
, int align
);
1591 static void XRotAddToLinkedList(Display
*dpy
, RotatedTextItem
*item
);
1592 static void XRotFreeTextItem(Display
*dpy
, RotatedTextItem
*item
);
1593 static XImage
*XRotMagnifyImage(Display
*dpy
, XImage
*ximage
);
1596 /* ---------------------------------------------------------------------- */
1599 /**************************************************************************/
1600 /* Routine to mimic `strdup()' (some machines don't have it) */
1601 /**************************************************************************/
1603 static char *my_strdup(char *str
)
1610 s
=(char *)malloc((unsigned)(strlen(str
)+1));
1618 /* ---------------------------------------------------------------------- */
1621 /**************************************************************************/
1622 /* Routine to replace `strtok' : this one returns a zero length string if */
1623 /* it encounters two consecutive delimiters */
1624 /**************************************************************************/
1626 static char *my_strtok(char *str1
, char *str2
)
1630 static int start
, len
;
1636 /* initialise if str1 not NULL */
1643 /* run out of tokens ? */
1647 /* loop through characters */
1648 for(i
=start
; i
<len
; i
++) {
1649 /* loop through delimiters */
1651 for(j
=0; j
<strlen(str2
); j
++)
1652 if(stext
[i
]==str2
[j
])
1669 /* ---------------------------------------------------------------------- */
1672 /**************************************************************************/
1673 /* Return version/copyright information */
1674 /**************************************************************************/
1676 float XRotVersion(char *str
, int n
)
1679 strncpy(str
, XV_COPYRIGHT
, n
);
1684 /* ---------------------------------------------------------------------- */
1687 /**************************************************************************/
1688 /* Set the font magnification factor for all subsequent operations */
1689 /**************************************************************************/
1691 void XRotSetMagnification(float m
)
1698 /* ---------------------------------------------------------------------- */
1701 /**************************************************************************/
1702 /* Set the padding used when calculating bounding boxes */
1703 /**************************************************************************/
1705 void XRotSetBoundingBoxPad(int p
)
1712 /* ---------------------------------------------------------------------- */
1715 /**************************************************************************/
1716 /* Create an XImage structure and allocate memory for it */
1717 /**************************************************************************/
1719 static XImage
*MakeXImage(Display
*dpy
, int w
, int h
)
1724 /* reserve memory for image */
1725 data
=(char *)calloc((unsigned)(((w
-1)/8+1)*h
), 1);
1729 /* create the XImage */
1730 I
=XCreateImage(dpy
, DefaultVisual(dpy
, DefaultScreen(dpy
)), 1, XYBitmap
,
1731 0, data
, w
, h
, 8, 0);
1735 I
->byte_order
=I
->bitmap_bit_order
=MSBFirst
;
1740 /* ---------------------------------------------------------------------- */
1743 /**************************************************************************/
1744 /* A front end to XRotPaintAlignedString: */
1745 /* -no alignment, no background */
1746 /**************************************************************************/
1748 int XRotDrawString(Display
*dpy
, XFontStruct
*font
, float angle
, Drawable drawable
, GC gc
, int x
, int y
, char *str
)
1750 return (XRotPaintAlignedString(dpy
, font
, angle
, drawable
, gc
,
1751 x
, y
, str
, NONE
, 0));
1755 /* ---------------------------------------------------------------------- */
1758 /**************************************************************************/
1759 /* A front end to XRotPaintAlignedString: */
1760 /* -no alignment, paints background */
1761 /**************************************************************************/
1763 int XRotDrawImageString(Display
*dpy
, XFontStruct
*font
, float angle
, Drawable drawable
, GC gc
, int x
, int y
, char *str
)
1765 return(XRotPaintAlignedString(dpy
, font
, angle
, drawable
, gc
,
1766 x
, y
, str
, NONE
, 1));
1770 /* ---------------------------------------------------------------------- */
1773 /**************************************************************************/
1774 /* A front end to XRotPaintAlignedString: */
1775 /* -does alignment, no background */
1776 /**************************************************************************/
1778 int XRotDrawAlignedString(Display
*dpy
, XFontStruct
*font
, float angle
, Drawable drawable
, GC gc
, int x
, int y
, char *text
, int align
)
1780 return(XRotPaintAlignedString(dpy
, font
, angle
, drawable
, gc
,
1781 x
, y
, text
, align
, 0));
1785 /* ---------------------------------------------------------------------- */
1788 /**************************************************************************/
1789 /* A front end to XRotPaintAlignedString: */
1790 /* -does alignment, paints background */
1791 /**************************************************************************/
1793 int XRotDrawAlignedImageString(Display
*dpy
, XFontStruct
*font
, float angle
, Drawable drawable
, GC gc
, int x
, int y
, char *text
, int align
)
1795 return(XRotPaintAlignedString(dpy
, font
, angle
, drawable
, gc
,
1796 x
, y
, text
, align
, 1));
1800 /* ---------------------------------------------------------------------- */
1803 /**************************************************************************/
1804 /* Aligns and paints a rotated string */
1805 /**************************************************************************/
1807 static int XRotPaintAlignedString(Display
*dpy
, XFontStruct
*font
, float angle
, Drawable drawable
, GC gc
, int x
, int y
, char *text
, int align
, int bg
)
1813 float hot_xp
, hot_yp
;
1814 float sin_angle
, cos_angle
;
1815 RotatedTextItem
*item
;
1816 Pixmap bitmap_to_paint
;
1818 /* return early for NULL/empty strings */
1825 /* manipulate angle to 0<=angle<360 degrees */
1834 /* horizontal text made easy */
1835 if(angle
==0. && style
.magnify
==1.)
1836 return(XRotDrawHorizontalString(dpy
, font
, drawable
, gc
, x
, y
,
1839 /* get a rotated bitmap */
1840 item
=XRotRetrieveFromCache(dpy
, font
, angle
, text
, align
);
1844 /* this gc has similar properties to the user's gc */
1845 my_gc
=XCreateGC(dpy
, drawable
, NULL
, 0);
1846 XCopyGC(dpy
, gc
, GCForeground
|GCBackground
|GCFunction
|GCPlaneMask
1847 |GCClipXOrigin
|GCClipYOrigin
|GCClipMask
, my_gc
);
1849 /* alignment : which point (hot_x, hot_y) relative to bitmap centre
1850 coincides with user's specified point? */
1853 if(align
==TLEFT
|| align
==TCENTRE
|| align
==TRIGHT
)
1854 hot_y
=(float)item
->rows_in
/2*style
.magnify
;
1855 else if(align
==MLEFT
|| align
==MCENTRE
|| align
==MRIGHT
)
1857 else if(align
==BLEFT
|| align
==BCENTRE
|| align
==BRIGHT
)
1858 hot_y
= -(float)item
->rows_in
/2*style
.magnify
;
1860 hot_y
= -((float)item
->rows_in
/2-(float)font
->descent
)*style
.magnify
;
1863 if(align
==TLEFT
|| align
==MLEFT
|| align
==BLEFT
|| align
==NONE
)
1864 hot_x
= -(float)item
->max_width
/2*style
.magnify
;
1865 else if(align
==TCENTRE
|| align
==MCENTRE
|| align
==BCENTRE
)
1868 hot_x
=(float)item
->max_width
/2*style
.magnify
;
1870 /* pre-calculate sin and cos */
1871 sin_angle
=sin(angle
);
1872 cos_angle
=cos(angle
);
1874 /* rotate hot_x and hot_y around bitmap centre */
1875 hot_xp
= hot_x
*cos_angle
- hot_y
*sin_angle
;
1876 hot_yp
= hot_x
*sin_angle
+ hot_y
*cos_angle
;
1878 /* text background will be drawn using XFillPolygon */
1882 Pixmap empty_stipple
;
1884 /* reserve space for XPoints */
1885 xpoints
=(XPoint
*)malloc((unsigned)(4*item
->nl
*sizeof(XPoint
)));
1889 /* rotate corner positions */
1890 for(i
=0; i
<4*item
->nl
; i
++) {
1891 xpoints
[i
].x
=(float)x
+ ( (item
->corners_x
[i
]-hot_x
)*cos_angle
+
1892 (item
->corners_y
[i
]+hot_y
)*sin_angle
);
1893 xpoints
[i
].y
=(float)y
+ (-(item
->corners_x
[i
]-hot_x
)*sin_angle
+
1894 (item
->corners_y
[i
]+hot_y
)*cos_angle
);
1897 /* we want to swap foreground and background colors here;
1898 XGetGCValues() is only available in R4+ */
1900 empty_stipple
=XCreatePixmap(dpy
, drawable
, 1, 1, 1);
1902 depth_one_gc
=XCreateGC(dpy
, empty_stipple
, NULL
, 0);
1903 XSetForeground(dpy
, depth_one_gc
, 0);
1904 XFillRectangle(dpy
, empty_stipple
, depth_one_gc
, 0, 0, 2, 2);
1906 XSetStipple(dpy
, my_gc
, empty_stipple
);
1907 XSetFillStyle(dpy
, my_gc
, FillOpaqueStippled
);
1909 XFillPolygon(dpy
, drawable
, my_gc
, xpoints
, 4*item
->nl
, Nonconvex
,
1912 /* free our resources */
1913 free((char *)xpoints
);
1914 XFreeGC(dpy
, depth_one_gc
);
1915 XFreePixmap(dpy
, empty_stipple
);
1918 /* where should top left corner of bitmap go ? */
1919 xp
=(float)x
-((float)item
->cols_out
/2 +hot_xp
);
1920 yp
=(float)y
-((float)item
->rows_out
/2 -hot_yp
);
1922 /* by default we draw the rotated bitmap, solid */
1923 bitmap_to_paint
=item
->bitmap
;
1925 /* handle user stippling */
1930 Pixmap new_bitmap
, inverse
;
1932 /* try and get some GC properties */
1933 if(XGetGCValues(dpy
, gc
,
1934 GCStipple
|GCFillStyle
|GCForeground
|GCBackground
|
1935 GCTileStipXOrigin
|GCTileStipYOrigin
,
1938 /* only do this if stippling requested */
1939 if((values
.fill_style
==FillStippled
||
1940 values
.fill_style
==FillOpaqueStippled
) && !bg
) {
1942 /* opaque stipple: draw rotated text in background colour */
1943 if(values
.fill_style
==FillOpaqueStippled
) {
1944 XSetForeground(dpy
, my_gc
, values
.background
);
1945 XSetFillStyle(dpy
, my_gc
, FillStippled
);
1946 XSetStipple(dpy
, my_gc
, item
->bitmap
);
1947 XSetTSOrigin(dpy
, my_gc
, xp
, yp
);
1948 XFillRectangle(dpy
, drawable
, my_gc
, xp
, yp
,
1949 item
->cols_out
, item
->rows_out
);
1950 XSetForeground(dpy
, my_gc
, values
.foreground
);
1953 /* this will merge the rotated text and the user's stipple */
1954 new_bitmap
=XCreatePixmap(dpy
, drawable
,
1955 item
->cols_out
, item
->rows_out
, 1);
1958 depth_one_gc
=XCreateGC(dpy
, new_bitmap
, NULL
, 0);
1959 XSetForeground(dpy
, depth_one_gc
, 1);
1960 XSetBackground(dpy
, depth_one_gc
, 0);
1962 /* set the relative stipple origin */
1963 XSetTSOrigin(dpy
, depth_one_gc
,
1964 values
.ts_x_origin
-xp
, values
.ts_y_origin
-yp
);
1966 /* fill the whole bitmap with the user's stipple */
1967 XSetStipple(dpy
, depth_one_gc
, values
.stipple
);
1968 XSetFillStyle(dpy
, depth_one_gc
, FillOpaqueStippled
);
1969 XFillRectangle(dpy
, new_bitmap
, depth_one_gc
,
1970 0, 0, item
->cols_out
, item
->rows_out
);
1972 /* set stipple origin back to normal */
1973 XSetTSOrigin(dpy
, depth_one_gc
, 0, 0);
1975 /* this will contain an inverse copy of the rotated text */
1976 inverse
=XCreatePixmap(dpy
, drawable
,
1977 item
->cols_out
, item
->rows_out
, 1);
1980 XSetFillStyle(dpy
, depth_one_gc
, FillSolid
);
1981 XSetFunction(dpy
, depth_one_gc
, GXcopyInverted
);
1982 XCopyArea(dpy
, item
->bitmap
, inverse
, depth_one_gc
,
1983 0, 0, item
->cols_out
, item
->rows_out
, 0, 0);
1985 /* now delete user's stipple everywhere EXCEPT on text */
1986 XSetForeground(dpy
, depth_one_gc
, 0);
1987 XSetBackground(dpy
, depth_one_gc
, 1);
1988 XSetStipple(dpy
, depth_one_gc
, inverse
);
1989 XSetFillStyle(dpy
, depth_one_gc
, FillStippled
);
1990 XSetFunction(dpy
, depth_one_gc
, GXcopy
);
1991 XFillRectangle(dpy
, new_bitmap
, depth_one_gc
,
1992 0, 0, item
->cols_out
, item
->rows_out
);
1994 /* free resources */
1995 XFreePixmap(dpy
, inverse
);
1996 XFreeGC(dpy
, depth_one_gc
);
1998 /* this is the new bitmap */
1999 bitmap_to_paint
=new_bitmap
;
2005 /* paint text using stipple technique */
2006 XSetFillStyle(dpy
, my_gc
, FillStippled
);
2007 XSetStipple(dpy
, my_gc
, bitmap_to_paint
);
2008 XSetTSOrigin(dpy
, my_gc
, xp
, yp
);
2009 XFillRectangle(dpy
, drawable
, my_gc
, xp
, yp
,
2010 item
->cols_out
, item
->rows_out
);
2012 /* free our resources */
2013 XFreeGC(dpy
, my_gc
);
2015 /* stippled bitmap no longer needed */
2016 if(bitmap_to_paint
!=item
->bitmap
)
2017 XFreePixmap(dpy
, bitmap_to_paint
);
2019 #ifdef CACHE_XIMAGES
2020 XFreePixmap(dpy
, item
->bitmap
);
2021 #endif /*CACHE_XIMAGES*/
2023 /* if item isn't cached, destroy it completely */
2025 XRotFreeTextItem(dpy
,item
);
2027 /* we got to the end OK! */
2032 /* ---------------------------------------------------------------------- */
2035 /**************************************************************************/
2036 /* Draw a horizontal string in a quick fashion */
2037 /**************************************************************************/
2039 static int XRotDrawHorizontalString(Display
*dpy
, XFontStruct
*font
, Drawable drawable
, GC gc
, int x
, int y
, char *text
, int align
, int bg
)
2045 char *str1
, *str2
, *str3
;
2046 char *str2_a
="\0", *str2_b
="\n\0";
2048 XCharStruct overall
;
2050 DEBUG_PRINT1("**\nHorizontal text.\n");
2052 /* this gc has similar properties to the user's gc (including stipple) */
2053 my_gc
=XCreateGC(dpy
, drawable
, NULL
, 0);
2055 GCForeground
|GCBackground
|GCFunction
|GCStipple
|GCFillStyle
|
2056 GCTileStipXOrigin
|GCTileStipYOrigin
|GCPlaneMask
|
2057 GCClipXOrigin
|GCClipYOrigin
|GCClipMask
, my_gc
);
2058 XSetFont(dpy
, my_gc
, font
->fid
);
2060 /* count number of sections in string */
2062 for(i
=0; i
<strlen(text
)-1; i
++)
2066 /* ignore newline characters if not doing alignment */
2072 /* overall font height */
2073 height
=font
->ascent
+font
->descent
;
2076 if(align
==TLEFT
|| align
==TCENTRE
|| align
==TRIGHT
)
2078 else if(align
==MLEFT
|| align
==MCENTRE
|| align
==MRIGHT
)
2079 yp
=y
-nl
*height
/2+font
->ascent
;
2080 else if(align
==BLEFT
|| align
==BCENTRE
|| align
==BRIGHT
)
2081 yp
=y
-nl
*height
+font
->ascent
;
2085 str1
=my_strdup(text
);
2089 str3
=my_strtok(str1
, str2
);
2091 /* loop through each section in the string */
2093 XTextExtents(font
, str3
, strlen(str3
), &dir
, &asc
, &desc
,
2096 /* where to draw section in x ? */
2097 if(align
==TLEFT
|| align
==MLEFT
|| align
==BLEFT
|| align
==NONE
)
2099 else if(align
==TCENTRE
|| align
==MCENTRE
|| align
==BCENTRE
)
2100 xp
=x
-overall
.rbearing
/2;
2102 xp
=x
-overall
.rbearing
;
2104 /* draw string onto bitmap */
2106 XDrawString(dpy
, drawable
, my_gc
, xp
, yp
, str3
, strlen(str3
));
2108 XDrawImageString(dpy
, drawable
, my_gc
, xp
, yp
, str3
, strlen(str3
));
2110 /* move to next line */
2113 str3
=my_strtok((char *)NULL
, str2
);
2118 XFreeGC(dpy
, my_gc
);
2124 /* ---------------------------------------------------------------------- */
2127 /**************************************************************************/
2128 /* Query cache for a match with this font/text/angle/alignment */
2129 /* request, otherwise arrange for its creation */
2130 /**************************************************************************/
2132 static RotatedTextItem
*XRotRetrieveFromCache(Display
*dpy
, XFontStruct
*font
, float angle
, char *text
, int align
)
2135 char *font_name
=NULL
;
2136 unsigned long name_value
;
2137 RotatedTextItem
*item
=NULL
;
2138 RotatedTextItem
*i1
=first_text_item
;
2140 /* get font name, if it exists */
2141 if(XGetFontProperty(font
, XA_FONT
, &name_value
)) {
2142 DEBUG_PRINT1("got font name OK\n");
2143 font_name
=XGetAtomName(dpy
, name_value
);
2147 /* otherwise rely (unreliably?) on font ID */
2149 DEBUG_PRINT1("can't get fontname, caching FID\n");
2154 /* not allowed to cache font ID's */
2156 DEBUG_PRINT1("can't get fontname, can't cache\n");
2160 #endif /*CACHE_FID*/
2162 /* look for a match in cache */
2164 /* matching formula:
2166 identical fontname (if defined, font ID's if not);
2167 angles close enough (<0.00001 here, could be smaller);
2168 HORIZONTAL alignment matches, OR it's a one line string;
2169 magnifications the same */
2171 while(i1
&& !item
) {
2172 /* match everything EXCEPT fontname/ID */
2173 if(strcmp(text
, i1
->text
)==0 &&
2174 fabs(angle
-i1
->angle
)<0.00001 &&
2175 style
.magnify
==i1
->magnify
&&
2177 ((align
==0)?9:(align
-1))%3==
2178 ((i1
->align
==0)?9:(i1
->align
-1))%3)) {
2180 /* now match fontname/ID */
2181 if(font_name
!=NULL
&& i1
->font_name
!=NULL
) {
2182 if(strcmp(font_name
, i1
->font_name
)==0) {
2184 DEBUG_PRINT1("Matched against font names\n");
2190 else if(font_name
==NULL
&& i1
->font_name
==NULL
) {
2193 DEBUG_PRINT1("Matched against FID's\n");
2198 #endif /*CACHE_FID*/
2207 DEBUG_PRINT1("**\nFound target in cache.\n");
2209 DEBUG_PRINT1("**\nNo match in cache.\n");
2213 /* create new item */
2214 item
=XRotCreateTextItem(dpy
, font
, angle
, text
, align
);
2218 /* record what it shows */
2219 item
->text
=my_strdup(text
);
2221 /* fontname or ID */
2222 if(font_name
!=NULL
) {
2223 item
->font_name
=my_strdup(font_name
);
2227 item
->font_name
=NULL
;
2233 item
->magnify
=style
.magnify
;
2236 XRotAddToLinkedList(dpy
, item
);
2242 /* if XImage is cached, need to recreate the bitmap */
2244 #ifdef CACHE_XIMAGES
2248 /* create bitmap to hold rotated text */
2249 item
->bitmap
=XCreatePixmap(dpy
, DefaultRootWindow(dpy
),
2250 item
->cols_out
, item
->rows_out
, 1);
2253 depth_one_gc
=XCreateGC(dpy
, item
->bitmap
, NULL
, 0);
2254 XSetBackground(dpy
, depth_one_gc
, 0);
2255 XSetForeground(dpy
, depth_one_gc
, 1);
2257 /* make the text bitmap from XImage */
2258 XPutImage(dpy
, item
->bitmap
, depth_one_gc
, item
->ximage
, 0, 0, 0, 0,
2259 item
->cols_out
, item
->rows_out
);
2261 XFreeGC(dpy
, depth_one_gc
);
2263 #endif /*CACHE_XIMAGES*/
2269 /* ---------------------------------------------------------------------- */
2272 /**************************************************************************/
2273 /* Create a rotated text item */
2274 /**************************************************************************/
2276 static RotatedTextItem
*XRotCreateTextItem(Display
*dpy
, XFontStruct
*font
, float angle
, char *text
, int align
)
2278 RotatedTextItem
*item
=NULL
;
2283 char *str1
, *str2
, *str3
;
2284 char *str2_a
="\0", *str2_b
="\n\0";
2286 int byte_w_in
, byte_w_out
;
2288 float sin_angle
, cos_angle
;
2295 XCharStruct overall
;
2296 int old_cols_in
=0, old_rows_in
=0;
2298 /* allocate memory */
2299 item
=(RotatedTextItem
*)malloc((unsigned)sizeof(RotatedTextItem
));
2303 /* count number of sections in string */
2306 for(i
=0; i
<strlen(text
)-1; i
++)
2310 /* ignore newline characters if not doing alignment */
2316 /* find width of longest section */
2317 str1
=my_strdup(text
);
2321 str3
=my_strtok(str1
, str2
);
2323 XTextExtents(font
, str3
, strlen(str3
), &dir
, &asc
, &desc
,
2326 item
->max_width
=overall
.rbearing
;
2328 /* loop through each section */
2330 str3
=my_strtok((char *)NULL
, str2
);
2333 XTextExtents(font
, str3
, strlen(str3
), &dir
, &asc
, &desc
,
2336 if(overall
.rbearing
>item
->max_width
)
2337 item
->max_width
=overall
.rbearing
;
2344 /* overall font height */
2345 height
=font
->ascent
+font
->descent
;
2347 /* dimensions horizontal text will have */
2348 item
->cols_in
=item
->max_width
;
2349 item
->rows_in
=item
->nl
*height
;
2351 /* bitmap for drawing on */
2352 canvas
=XCreatePixmap(dpy
, DefaultRootWindow(dpy
),
2353 item
->cols_in
, item
->rows_in
, 1);
2355 /* create a GC for the bitmap */
2356 font_gc
=XCreateGC(dpy
, canvas
, NULL
, 0);
2357 XSetBackground(dpy
, font_gc
, 0);
2358 XSetFont(dpy
, font_gc
, font
->fid
);
2360 /* make sure the bitmap is blank */
2361 XSetForeground(dpy
, font_gc
, 0);
2362 XFillRectangle(dpy
, canvas
, font_gc
, 0, 0,
2363 item
->cols_in
+1, item
->rows_in
+1);
2364 XSetForeground(dpy
, font_gc
, 1);
2366 /* pre-calculate sin and cos */
2367 sin_angle
=sin(angle
);
2368 cos_angle
=cos(angle
);
2370 /* text background will be drawn using XFillPolygon */
2372 (float *)malloc((unsigned)(4*item
->nl
*sizeof(float)));
2373 if(!item
->corners_x
)
2377 (float *)malloc((unsigned)(4*item
->nl
*sizeof(float)));
2378 if(!item
->corners_y
)
2381 /* draw text horizontally */
2383 /* start at top of bitmap */
2386 str1
=my_strdup(text
);
2390 str3
=my_strtok(str1
, str2
);
2392 /* loop through each section in the string */
2394 XTextExtents(font
, str3
, strlen(str3
), &dir
, &asc
, &desc
,
2397 /* where to draw section in x ? */
2398 if(align
==TLEFT
|| align
==MLEFT
|| align
==BLEFT
|| align
==NONE
)
2400 else if(align
==TCENTRE
|| align
==MCENTRE
|| align
==BCENTRE
)
2401 xp
=(item
->max_width
-overall
.rbearing
)/2;
2403 xp
=item
->max_width
-overall
.rbearing
;
2405 /* draw string onto bitmap */
2406 XDrawString(dpy
, canvas
, font_gc
, xp
, yp
, str3
, strlen(str3
));
2408 /* keep a note of corner positions of this string */
2409 item
->corners_x
[ic
]=((float)xp
-(float)item
->cols_in
/2)*style
.magnify
;
2410 item
->corners_y
[ic
]=((float)(yp
-font
->ascent
)-(float)item
->rows_in
/2)
2412 item
->corners_x
[ic
+1]=item
->corners_x
[ic
];
2413 item
->corners_y
[ic
+1]=item
->corners_y
[ic
]+(float)height
*style
.magnify
;
2414 item
->corners_x
[item
->nl
*4-1-ic
]=item
->corners_x
[ic
]+
2415 (float)overall
.rbearing
*style
.magnify
;
2416 item
->corners_y
[item
->nl
*4-1-ic
]=item
->corners_y
[ic
];
2417 item
->corners_x
[item
->nl
*4-2-ic
]=
2418 item
->corners_x
[item
->nl
*4-1-ic
];
2419 item
->corners_y
[item
->nl
*4-2-ic
]=item
->corners_y
[ic
+1];
2423 /* move to next line */
2426 str3
=my_strtok((char *)NULL
, str2
);
2432 /* create image to hold horizontal text */
2433 I_in
=MakeXImage(dpy
, item
->cols_in
, item
->rows_in
);
2437 /* extract horizontal text */
2438 XGetSubImage(dpy
, canvas
, 0, 0, item
->cols_in
, item
->rows_in
,
2439 1, XYPixmap
, I_in
, 0, 0);
2440 I_in
->format
=XYBitmap
;
2442 /* magnify horizontal text */
2443 if(style
.magnify
!=1.) {
2444 I_in
=XRotMagnifyImage(dpy
, I_in
);
2446 old_cols_in
=item
->cols_in
;
2447 old_rows_in
=item
->rows_in
;
2448 item
->cols_in
=(float)item
->cols_in
*style
.magnify
;
2449 item
->rows_in
=(float)item
->rows_in
*style
.magnify
;
2452 /* how big will rotated text be ? */
2453 item
->cols_out
=fabs((float)item
->rows_in
*sin_angle
) +
2454 fabs((float)item
->cols_in
*cos_angle
) +0.99999 +2;
2456 item
->rows_out
=fabs((float)item
->rows_in
*cos_angle
) +
2457 fabs((float)item
->cols_in
*sin_angle
) +0.99999 +2;
2459 if(item
->cols_out
%2==0)
2462 if(item
->rows_out
%2==0)
2465 /* create image to hold rotated text */
2466 item
->ximage
=MakeXImage(dpy
, item
->cols_out
, item
->rows_out
);
2467 if(item
->ximage
==NULL
)
2470 byte_w_in
=(item
->cols_in
-1)/8+1;
2471 byte_w_out
=(item
->cols_out
-1)/8+1;
2473 /* we try to make this bit as fast as possible - which is why it looks
2474 a bit over-the-top */
2476 /* vertical distance from centre */
2477 dj
=0.5-(float)item
->rows_out
/2;
2479 /* where abouts does text actually lie in rotated image? */
2480 if(angle
==0 || angle
==M_PI
/2 ||
2481 angle
==M_PI
|| angle
==3*M_PI
/2) {
2483 xr
=(float)item
->cols_out
;
2486 else if(angle
<M_PI
) {
2487 xl
=(float)item
->cols_out
/2+
2488 (dj
-(float)item
->rows_in
/(2*cos_angle
))/
2490 xr
=(float)item
->cols_out
/2+
2491 (dj
+(float)item
->rows_in
/(2*cos_angle
))/
2496 xl
=(float)item
->cols_out
/2+
2497 (dj
+(float)item
->rows_in
/(2*cos_angle
))/
2499 xr
=(float)item
->cols_out
/2+
2500 (dj
-(float)item
->rows_in
/(2*cos_angle
))/
2506 /* loop through all relevent bits in rotated image */
2507 for(j
=0; j
<item
->rows_out
; j
++) {
2509 /* no point re-calculating these every pass */
2510 di
=(float)((xl
<0)?0:(int)xl
)+0.5-(float)item
->cols_out
/2;
2511 byte_out
=(item
->rows_out
-j
-1)*byte_w_out
;
2513 /* loop through meaningful columns */
2514 for(i
=((xl
<0)?0:(int)xl
);
2515 i
<((xr
>=item
->cols_out
)?item
->cols_out
:(int)xr
); i
++) {
2517 /* rotate coordinates */
2518 it
=(float)item
->cols_in
/2 + ( di
*cos_angle
+ dj
*sin_angle
);
2519 jt
=(float)item
->rows_in
/2 - (-di
*sin_angle
+ dj
*cos_angle
);
2521 /* set pixel if required */
2522 if(it
>=0 && it
<item
->cols_in
&& jt
>=0 && jt
<item
->rows_in
)
2523 if((I_in
->data
[jt
*byte_w_in
+it
/8] & 128>>(it
%8))>0)
2524 item
->ximage
->data
[byte_out
+i
/8]|=128>>i
%8;
2532 XDestroyImage(I_in
);
2534 if(style
.magnify
!=1.) {
2535 item
->cols_in
=old_cols_in
;
2536 item
->rows_in
=old_rows_in
;
2540 #ifdef CACHE_BITMAPS
2542 /* create a bitmap to hold rotated text */
2543 item
->bitmap
=XCreatePixmap(dpy
, DefaultRootWindow(dpy
),
2544 item
->cols_out
, item
->rows_out
, 1);
2546 /* make the text bitmap from XImage */
2547 XPutImage(dpy
, item
->bitmap
, font_gc
, item
->ximage
, 0, 0, 0, 0,
2548 item
->cols_out
, item
->rows_out
);
2550 XDestroyImage(item
->ximage
);
2552 #endif /*CACHE_BITMAPS*/
2554 XFreeGC(dpy
, font_gc
);
2555 XFreePixmap(dpy
, canvas
);
2561 /* ---------------------------------------------------------------------- */
2564 /**************************************************************************/
2565 /* Adds a text item to the end of the cache, removing as many items */
2566 /* from the front as required to keep cache size below limit */
2567 /**************************************************************************/
2569 static void XRotAddToLinkedList(Display
*dpy
, RotatedTextItem
*item
)
2572 static long int current_size
=0;
2573 static RotatedTextItem
*last
=NULL
;
2574 RotatedTextItem
*i1
=first_text_item
, *i2
=NULL
;
2576 #ifdef CACHE_BITMAPS
2578 /* I don't know how much memory a pixmap takes in the server -
2579 probably this + a bit more we can't account for */
2581 item
->size
=((item
->cols_out
-1)/8+1)*item
->rows_out
;
2585 /* this is pretty much the size of a RotatedTextItem */
2587 item
->size
=((item
->cols_out
-1)/8+1)*item
->rows_out
+
2588 sizeof(XImage
) + strlen(item
->text
) +
2589 item
->nl
*8*sizeof(float) + sizeof(RotatedTextItem
);
2591 if(item
->font_name
!=NULL
)
2592 item
->size
+=strlen(item
->font_name
);
2594 item
->size
+=sizeof(Font
);
2596 #endif /*CACHE_BITMAPS */
2599 /* count number of items in cache, for debugging */
2607 DEBUG_PRINT2("Cache has %d items.\n", i
);
2612 DEBUG_PRINT4("current cache size=%ld, new item=%ld, limit=%ld\n",
2613 current_size
, item
->size
, CACHE_SIZE_LIMIT
*1024);
2615 /* if this item is bigger than whole cache, forget it */
2616 if(item
->size
>CACHE_SIZE_LIMIT
*1024) {
2617 DEBUG_PRINT1("Too big to cache\n\n");
2622 /* remove elements from cache as needed */
2623 while(i1
&& current_size
+item
->size
>CACHE_SIZE_LIMIT
*1024) {
2625 DEBUG_PRINT2("Removed %d bytes\n", i1
->size
);
2627 if(i1
->font_name
!=NULL
)
2628 DEBUG_PRINT5(" (`%s'\n %s\n angle=%f align=%d)\n",
2629 i1
->text
, i1
->font_name
, i1
->angle
, i1
->align
);
2632 if(i1
->font_name
==NULL
)
2633 DEBUG_PRINT5(" (`%s'\n FID=%ld\n angle=%f align=%d)\n",
2634 i1
->text
, i1
->fid
, i1
->angle
, i1
->align
);
2635 #endif /*CACHE_FID*/
2637 current_size
-=i1
->size
;
2641 /* free resources used by the unlucky item */
2642 XRotFreeTextItem(dpy
, i1
);
2644 /* remove it from linked list */
2649 /* add new item to end of linked list */
2650 if(first_text_item
==NULL
) {
2652 first_text_item
=item
;
2661 /* new cache size */
2662 current_size
+=item
->size
;
2666 DEBUG_PRINT1("Added item to cache.\n");
2670 /* ---------------------------------------------------------------------- */
2673 /**************************************************************************/
2674 /* Free the resources used by a text item */
2675 /**************************************************************************/
2677 static void XRotFreeTextItem(Display
*dpy
, RotatedTextItem
*item
)
2681 if(item
->font_name
!=NULL
)
2682 free(item
->font_name
);
2684 free((char *)item
->corners_x
);
2685 free((char *)item
->corners_y
);
2687 #ifdef CACHE_BITMAPS
2688 XFreePixmap(dpy
, item
->bitmap
);
2690 XDestroyImage(item
->ximage
);
2691 #endif /* CACHE_BITMAPS */
2697 /* ---------------------------------------------------------------------- */
2700 /**************************************************************************/
2701 /* Magnify an XImage using bilinear interpolation */
2702 /**************************************************************************/
2704 static XImage
*XRotMagnifyImage(Display
*dpy
, XImage
*ximage
)
2710 int cols_in
, rows_in
;
2711 int cols_out
, rows_out
;
2712 register int i2
, j2
;
2713 float z1
, z2
, z3
, z4
;
2714 int byte_width_in
, byte_width_out
;
2717 /* size of input image */
2718 cols_in
=ximage
->width
;
2719 rows_in
=ximage
->height
;
2721 /* size of final image */
2722 cols_out
=(float)cols_in
*style
.magnify
;
2723 rows_out
=(float)rows_in
*style
.magnify
;
2725 /* this will hold final image */
2726 I_out
=MakeXImage(dpy
, cols_out
, rows_out
);
2730 /* width in bytes of input, output images */
2731 byte_width_in
=(cols_in
-1)/8+1;
2732 byte_width_out
=(cols_out
-1)/8+1;
2735 mag_inv
=1./style
.magnify
;
2739 /* loop over magnified image */
2740 for(j2
=0; j2
<rows_out
; j2
++) {
2744 for(i2
=0; i2
<cols_out
; i2
++) {
2747 /* bilinear interpolation - where are we on bitmap ? */
2749 if(i
==cols_in
-1 && j
!=rows_in
-1) {
2753 z1
=(ximage
->data
[j
*byte_width_in
+i
/8] & 128>>(i
%8))>0;
2755 z3
=(ximage
->data
[(j
+1)*byte_width_in
+i
/8] & 128>>(i
%8))>0;
2759 else if(i
!=cols_in
-1 && j
==rows_in
-1) {
2763 z1
=(ximage
->data
[j
*byte_width_in
+i
/8] & 128>>(i
%8))>0;
2764 z2
=(ximage
->data
[j
*byte_width_in
+(i
+1)/8] & 128>>((i
+1)%8))>0;
2768 /* top right corner */
2769 else if(i
==cols_in
-1 && j
==rows_in
-1) {
2773 z1
=(ximage
->data
[j
*byte_width_in
+i
/8] & 128>>(i
%8))>0;
2778 /* somewhere `safe' */
2783 z1
=(ximage
->data
[j
*byte_width_in
+i
/8] & 128>>(i
%8))>0;
2784 z2
=(ximage
->data
[j
*byte_width_in
+(i
+1)/8] & 128>>((i
+1)%8))>0;
2785 z3
=(ximage
->data
[(j
+1)*byte_width_in
+(i
+1)/8] &
2787 z4
=(ximage
->data
[(j
+1)*byte_width_in
+i
/8] & 128>>(i
%8))>0;
2790 /* if interpolated value is greater than 0.5, set bit */
2791 if(((1-t
)*(1-u
)*z1
+ t
*(1-u
)*z2
+ t
*u
*z3
+ (1-t
)*u
*z4
)>0.5)
2792 I_out
->data
[j2
*byte_width_out
+i2
/8]|=128>>i2
%8;
2799 /* destroy original */
2800 XDestroyImage(ximage
);
2802 /* return big image */
2808 /* ---------------------------------------------------------------------- */
2811 /**************************************************************************/
2812 /* Calculate the bounding box some text will have when painted */
2813 /**************************************************************************/
2815 XPoint
*XRotTextExtents(Display
*dpy
, XFontStruct
*font
, float angle
, int x
, int y
, char *text
, int align
)
2818 char *str1
, *str2
, *str3
;
2819 char *str2_a
="\0", *str2_b
="\n\0";
2821 float sin_angle
, cos_angle
;
2823 int cols_in
, rows_in
;
2825 XPoint
*xp_in
, *xp_out
;
2827 XCharStruct overall
;
2829 /* manipulate angle to 0<=angle<360 degrees */
2838 /* count number of sections in string */
2841 for(i
=0; i
<strlen(text
)-1; i
++)
2845 /* ignore newline characters if not doing alignment */
2851 /* find width of longest section */
2852 str1
=my_strdup(text
);
2856 str3
=my_strtok(str1
, str2
);
2858 XTextExtents(font
, str3
, strlen(str3
), &dir
, &asc
, &desc
,
2861 max_width
=overall
.rbearing
;
2863 /* loop through each section */
2865 str3
=my_strtok((char *)NULL
, str2
);
2868 XTextExtents(font
, str3
, strlen(str3
), &dir
, &asc
, &desc
,
2871 if(overall
.rbearing
>max_width
)
2872 max_width
=overall
.rbearing
;
2879 /* overall font height */
2880 height
=font
->ascent
+font
->descent
;
2882 /* dimensions horizontal text will have */
2886 /* pre-calculate sin and cos */
2887 sin_angle
=sin(angle
);
2888 cos_angle
=cos(angle
);
2891 if(align
==TLEFT
|| align
==TCENTRE
|| align
==TRIGHT
)
2892 hot_y
=(float)rows_in
/2*style
.magnify
;
2893 else if(align
==MLEFT
|| align
==MCENTRE
|| align
==MRIGHT
)
2895 else if(align
==BLEFT
|| align
==BCENTRE
|| align
==BRIGHT
)
2896 hot_y
= -(float)rows_in
/2*style
.magnify
;
2898 hot_y
= -((float)rows_in
/2-(float)font
->descent
)*style
.magnify
;
2901 if(align
==TLEFT
|| align
==MLEFT
|| align
==BLEFT
|| align
==NONE
)
2902 hot_x
= -(float)max_width
/2*style
.magnify
;
2903 else if(align
==TCENTRE
|| align
==MCENTRE
|| align
==BCENTRE
)
2906 hot_x
=(float)max_width
/2*style
.magnify
;
2908 /* reserve space for XPoints */
2909 xp_in
=(XPoint
*)malloc((unsigned)(5*sizeof(XPoint
)));
2913 xp_out
=(XPoint
*)malloc((unsigned)(5*sizeof(XPoint
)));
2917 /* bounding box when horizontal, relative to bitmap centre */
2918 xp_in
[0].x
= -(float)cols_in
*style
.magnify
/2-style
.bbx_pad
;
2919 xp_in
[0].y
= (float)rows_in
*style
.magnify
/2+style
.bbx_pad
;
2920 xp_in
[1].x
= (float)cols_in
*style
.magnify
/2+style
.bbx_pad
;
2921 xp_in
[1].y
= (float)rows_in
*style
.magnify
/2+style
.bbx_pad
;
2922 xp_in
[2].x
= (float)cols_in
*style
.magnify
/2+style
.bbx_pad
;
2923 xp_in
[2].y
= -(float)rows_in
*style
.magnify
/2-style
.bbx_pad
;
2924 xp_in
[3].x
= -(float)cols_in
*style
.magnify
/2-style
.bbx_pad
;
2925 xp_in
[3].y
= -(float)rows_in
*style
.magnify
/2-style
.bbx_pad
;
2926 xp_in
[4].x
=xp_in
[0].x
;
2927 xp_in
[4].y
=xp_in
[0].y
;
2929 /* rotate and translate bounding box */
2930 for(i
=0; i
<5; i
++) {
2931 xp_out
[i
].x
=(float)x
+ ( ((float)xp_in
[i
].x
-hot_x
)*cos_angle
+
2932 ((float)xp_in
[i
].y
+hot_y
)*sin_angle
);
2933 xp_out
[i
].y
=(float)y
+ (-((float)xp_in
[i
].x
-hot_x
)*sin_angle
+
2934 ((float)xp_in
[i
].y
+hot_y
)*cos_angle
);
2937 free((char *)xp_in
);
2944 /* ***********************************************************************
2945 * Conversion routines for the X resource manager
2946 * ***********************************************************************
2949 #if defined(__STDC__)
2951 Boolean
strtocard( Display
*dsp
,
2960 Boolean
strtocard( dsp
, args
, num_args
, from
, to
, unused
)
2969 static Cardinal temp
;
2971 if ( to
->addr
== NULL
) {
2972 to
->addr
= (XtPointer
) &temp
;
2973 to
->size
= sizeof(Cardinal
);
2976 *((Cardinal
*) to
->addr
) = atoi( from
->addr
);
2981 #define done_bert(type, value) \
2983 if (to->addr != NULL) {\
2984 if (to->size < sizeof(type)) {\
2985 to->size = sizeof(type);\
2988 *(type*)(to->addr) = (value);\
2990 static type static_val;\
2991 static_val = (value);\
2992 to->addr = (XtPointer)&static_val;\
2994 to->size = sizeof(type);\
2998 Boolean
cvtStringToStringArray(Display
*display
, XrmValuePtr args
, Cardinal
*num_args
, XrmValuePtr from
, XrmValuePtr to
, XtPointer
*converter_data
)
3001 StringArray a
= NULL
;
3006 XtAppErrorMsg(XtDisplayToApplicationContext(display
),
3007 "cvtStringToStringArray", "wrongParameters",
3009 "String to StringArray conversion needs no arguments",
3010 (String
*) NULL
, (Cardinal
*) NULL
);
3012 delim
= ((String
) from
->addr
)[0];
3013 s
= XtNewString((String
) from
->addr
+ 1);
3016 t
= strchr(s
, delim
);
3018 a
= (StringArray
) XtRealloc((String
) a
, (i
+ 1) * sizeof(*a
));
3021 s
= t
? t
+ 1 : NULL
;
3023 a
= (StringArray
) XtRealloc((String
) a
, (i
+ 1) * sizeof(*a
));
3025 done_bert(StringArray
, a
);
3029 /* ***********************************************************************
3030 * A driver for the above in the flavor of the xt utilities module
3031 * ***********************************************************************
3036 typedef struct tab_data
{
3040 void (*activate_func
)();
3044 #if defined(__STDC__)
3045 static void handle_click( Widget w
, TabData td
, XtPointer call_data
)
3047 static void handle_click(w
, td
, call_data
)
3050 XtPointer call_data
;
3053 int tab
= (int) call_data
;
3055 /* note that the tab is relative to the current tab.
3056 * if tab is 0, the user clicked on the current one.
3057 * there is nothing to do
3059 if (tab
== 0) return;
3062 /* Change tabs. We must manually inform the UI which tab is current */
3064 XtNlefttabs
, td
->cur
,
3065 XtNrighttabs
, td
->num_tabs
- td
->cur
- 1,
3069 (*td
->activate_func
)( td
->form
, td
->cur
);
3074 * PUBLIC: Widget __vi_CreateTabbedFolder
3075 * PUBLIC: __P((String, Widget, String, int, void (*)(Widget, int)));
3077 #if defined(__STDC__)
3078 Widget
__vi_CreateTabbedFolder( String name
,
3082 void (*activate_func
)()
3085 Widget
__vi_CreateTabbedFolder( name
, parent
, tab_labels
, num_tabs
, activate_func
)
3090 void (*activate_func
)();
3094 TabData td
= (TabData
) malloc( sizeof(struct tab_data
) );
3097 XtAppSetTypeConverter( XtDisplayToApplicationContext(XtDisplay(parent
)),
3107 /* init our internal structure */
3109 td
->num_tabs
= num_tabs
;
3110 td
->activate_func
= activate_func
;
3112 /* tabs go on the top */
3113 tabs
= XtVaCreateManagedWidget( "tabs",
3117 XtNrighttabs
, num_tabs
-1,
3118 XtNorientation
, XfwfUpTabs
,
3119 XmNtopAttachment
, XmATTACH_FORM
,
3120 XmNleftAttachment
, XmATTACH_FORM
,
3121 XmNleftOffset
, TABHT
/4,
3122 XmNrightAttachment
,XmATTACH_FORM
,
3123 XmNrightOffset
, TABHT
/4,
3124 XmNbottomAttachment
,XmATTACH_OPPOSITE_FORM
,
3125 XmNbottomOffset
, -TABHT
,
3126 XtNlabels
, tab_labels
,
3127 XtVaTypedArg
, XtNlabels
,
3130 strlen(tab_labels
) + 1,
3134 /* add the callback */
3135 XtAddCallback( tabs
,
3136 XtNactivateCallback
,
3137 (XtCallbackProc
) handle_click
,
3141 /* another form to hold the controls */
3142 td
->form
= XtVaCreateWidget( "form",
3145 XmNtopAttachment
, XmATTACH_WIDGET
,
3147 XmNleftAttachment
, XmATTACH_FORM
,
3148 XmNbottomAttachment
, XmATTACH_FORM
,
3149 XmNrightAttachment
, XmATTACH_FORM
,