use three-argument AC_DEFINE instead of acconfig.h
[nvi.git] / motif_l / xtabbed.c
blob3c83f455466093fa049e7d4102641f1cd1e4d142
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 * ***********************************************************************
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <Xm/Xm.h>
17 #include <Xm/Form.h>
18 #include <Xm/RowColumn.h>
19 #include <X11/StringDefs.h>
20 #include <X11/IntrinsicP.h>
21 #if defined(VMS_HOST)
22 #include <DECW$INCLUDE/shape.h>
23 #else
24 #include <X11/extensions/shape.h>
25 #endif
26 #include <X11/Xlib.h>
27 #include <X11/Xutil.h>
28 #include <X11/Xatom.h>
29 #include <math.h>
32 /* ***********************************************************************
33 * "rotated.h"
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 /* ---------------------------------------------------------------------- */
59 /* text alignment */
61 #define NONE 0
62 #define TLEFT 1
63 #define TCENTRE 2
64 #define TRIGHT 3
65 #define MLEFT 4
66 #define MCENTRE 5
67 #define MRIGHT 6
68 #define BLEFT 7
69 #define BCENTRE 8
70 #define BRIGHT 9
73 /* ---------------------------------------------------------------------- */
75 /* this shoulf be C++ compliant, thanks to
76 vlp@latina.inesc.pt (Vasco Lopes Paulo) */
78 #if defined(__cplusplus) || defined(c_plusplus)
80 extern "C" {
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);
96 #else
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 /* ***********************************************************************
118 * "strarray.h"
119 * ***********************************************************************
122 #ifndef _strarray_h_
123 #define _strarray_h_
125 StringArray
126 ===========
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
138 parts of the string.
140 The delimiter character is the first character in the string.
143 newStringArray
144 ==============
145 The function |newStringArray| makes a copy of a |StringArray|. It
146 allocates new space for the array itself and for the strings that
147 it contains.
150 freeStringArray
151 ===============
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
164 Display *display,
165 XrmValuePtr args,
166 Cardinal *num_args,
167 XrmValuePtr from,
168 XrmValuePtr to,
169 XtPointer *converter_data
170 #endif
174 StringArray newStringArray(
175 #if NeedFunctionPrototypes
176 StringArray a
177 #endif
181 void freeStringArray(
182 #if NeedFunctionPrototypes
183 StringArray a
184 #endif
188 #endif /* _strarray_h_ */
191 /* ***********************************************************************
192 * "XmTabs.h"
193 * ***********************************************************************
196 /* Generated by wbuild from "XmTabs.w"
197 ** (generator version $Revision: 8.5 $ of $Date: 2001/06/25 15:19:28 $)
199 #ifndef _XmTabs_H_
200 #define _XmTabs_H_
201 typedef enum {
202 XfwfUpTabs, XfwfDownTabs, XfwfLeftTabs, XfwfRightTabs,
203 } TabsOrientation;
205 #ifndef XtNorientation
206 #define XtNorientation "orientation"
207 #endif
208 #ifndef XtCOrientation
209 #define XtCOrientation "Orientation"
210 #endif
211 #ifndef XtRTabsOrientation
212 #define XtRTabsOrientation "TabsOrientation"
213 #endif
215 #ifndef XtNlefttabs
216 #define XtNlefttabs "lefttabs"
217 #endif
218 #ifndef XtCLefttabs
219 #define XtCLefttabs "Lefttabs"
220 #endif
221 #ifndef XtRInt
222 #define XtRInt "Int"
223 #endif
225 #ifndef XtNrighttabs
226 #define XtNrighttabs "righttabs"
227 #endif
228 #ifndef XtCRighttabs
229 #define XtCRighttabs "Righttabs"
230 #endif
231 #ifndef XtRInt
232 #define XtRInt "Int"
233 #endif
235 #ifndef XtNlabels
236 #define XtNlabels "labels"
237 #endif
238 #ifndef XtCLabels
239 #define XtCLabels "Labels"
240 #endif
241 #ifndef XtRStringArray
242 #define XtRStringArray "StringArray"
243 #endif
245 #ifndef XtNtabWidthPercentage
246 #define XtNtabWidthPercentage "tabWidthPercentage"
247 #endif
248 #ifndef XtCTabWidthPercentage
249 #define XtCTabWidthPercentage "TabWidthPercentage"
250 #endif
251 #ifndef XtRInt
252 #define XtRInt "Int"
253 #endif
255 #ifndef XtNcornerwidth
256 #define XtNcornerwidth "cornerwidth"
257 #endif
258 #ifndef XtCCornerwidth
259 #define XtCCornerwidth "Cornerwidth"
260 #endif
261 #ifndef XtRCardinal
262 #define XtRCardinal "Cardinal"
263 #endif
265 #ifndef XtNcornerheight
266 #define XtNcornerheight "cornerheight"
267 #endif
268 #ifndef XtCCornerheight
269 #define XtCCornerheight "Cornerheight"
270 #endif
271 #ifndef XtRCardinal
272 #define XtRCardinal "Cardinal"
273 #endif
275 #ifndef XtNtextmargin
276 #define XtNtextmargin "textmargin"
277 #endif
278 #ifndef XtCTextmargin
279 #define XtCTextmargin "Textmargin"
280 #endif
281 #ifndef XtRInt
282 #define XtRInt "Int"
283 #endif
285 #ifndef XtNtabcolor
286 #define XtNtabcolor "tabcolor"
287 #endif
288 #ifndef XtCTabcolor
289 #define XtCTabcolor "Tabcolor"
290 #endif
291 #ifndef XtRPixel
292 #define XtRPixel "Pixel"
293 #endif
295 #ifndef XtNfont
296 #define XtNfont "font"
297 #endif
298 #ifndef XtCFont
299 #define XtCFont "Font"
300 #endif
301 #ifndef XtRFontStruct
302 #define XtRFontStruct "FontStruct"
303 #endif
305 #ifndef XtNactivateCallback
306 #define XtNactivateCallback "activateCallback"
307 #endif
308 #ifndef XtCActivateCallback
309 #define XtCActivateCallback "ActivateCallback"
310 #endif
311 #ifndef XtRCallback
312 #define XtRCallback "Callback"
313 #endif
315 typedef struct _XmTabsClassRec *XmTabsWidgetClass;
316 typedef struct _XmTabsRec *XmTabsWidget;
317 #endif /*_XmTabs_H_*/
320 /* ***********************************************************************
321 * "XmTabsP.h"
322 * ***********************************************************************
325 /* Generated by wbuild from "XmTabs.w"
326 ** (generator version $Revision: 8.5 $ of $Date: 2001/06/25 15:19:28 $)
328 #ifndef _XmTabsP_H_
329 #define _XmTabsP_H_
331 /* raz modified 22 Jul 96 for bluestone */
332 #include <Xm/XmP.h>
333 #if ! defined(MGR_ShadowThickness)
334 #include <Xm/ManagerP.h>
335 #endif
337 typedef void (*border_highlight_Proc)(
338 #if NeedFunctionPrototypes
339 void
340 #endif
342 #define XtInherit_border_highlight ((border_highlight_Proc) _XtInherit)
343 typedef void (*border_unhighlight_Proc)(
344 #if NeedFunctionPrototypes
345 void
346 #endif
348 #define XtInherit_border_unhighlight ((border_unhighlight_Proc) _XtInherit)
349 typedef struct {
350 /* Constraint resources */
351 /* Private constraint variables */
352 int dummy;
353 } XmTabsConstraintPart;
355 typedef struct _XmTabsConstraintRec {
356 XmManagerConstraintPart xmManager;
357 XmTabsConstraintPart xmTabs;
358 } XmTabsConstraintRec;
361 typedef struct {
362 /* methods */
363 border_highlight_Proc border_highlight;
364 border_unhighlight_Proc border_unhighlight;
365 /* class variables */
366 } XmTabsClassPart;
368 typedef struct _XmTabsClassRec {
369 CoreClassPart core_class;
370 CompositeClassPart composite_class;
371 ConstraintClassPart constraint_class;
372 XmManagerClassPart xmManager_class;
373 XmTabsClassPart xmTabs_class;
374 } XmTabsClassRec;
376 typedef struct {
377 /* resources */
378 TabsOrientation orientation;
379 int lefttabs;
380 int righttabs;
381 StringArray labels;
382 int tabWidthPercentage;
383 Cardinal cornerwidth;
384 Cardinal cornerheight;
385 int textmargin;
386 Pixel tabcolor;
387 XFontStruct * font;
388 XtCallbackList activateCallback;
389 /* private state */
390 GC textgc;
391 GC topgc;
392 GC bottomgc;
393 GC backgc;
394 GC fillgc;
395 int * tabwidths;
396 int * offsets;
397 } XmTabsPart;
399 typedef struct _XmTabsRec {
400 CorePart core;
401 CompositePart composite;
402 ConstraintPart constraint;
403 XmManagerPart xmManager;
404 XmTabsPart xmTabs;
405 } XmTabsRec;
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*
418 #endif
421 static XtActionsRec actionsList[] = {
422 {"activate", activate},
425 static char defaultTranslations[] = "\
426 <Btn1Down>,<Btn1Up>: activate() \n\
428 static void _resolve_inheritance(
429 #if NeedFunctionPrototypes
430 WidgetClass
431 #endif
433 static void class_initialize(
434 #if NeedFunctionPrototypes
435 void
436 #endif
438 static void initialize(
439 #if NeedFunctionPrototypes
440 Widget ,Widget,ArgList ,Cardinal *
441 #endif
443 static Boolean set_values(
444 #if NeedFunctionPrototypes
445 Widget ,Widget ,Widget,ArgList ,Cardinal *
446 #endif
448 static void realize(
449 #if NeedFunctionPrototypes
450 Widget,XtValueMask *,XSetWindowAttributes *
451 #endif
453 static void resize(
454 #if NeedFunctionPrototypes
455 Widget
456 #endif
458 static void expose(
459 #if NeedFunctionPrototypes
460 Widget,XEvent *,Region
461 #endif
463 static void border_highlight(
464 #if NeedFunctionPrototypes
465 void
466 #endif
468 static void border_unhighlight(
469 #if NeedFunctionPrototypes
470 void
471 #endif
473 static void destroy(
474 #if NeedFunctionPrototypes
475 Widget
476 #endif
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
486 Widget
487 #endif
489 static void comp_hor_tab_shape(
490 #if NeedFunctionPrototypes
491 Widget,int ,XPoint p[12],int *,int *,int *
492 #endif
494 static void comp_ver_tab_shape(
495 #if NeedFunctionPrototypes
496 Widget,int ,XPoint p[12],int *,int *,int *
497 #endif
499 static void draw_border(
500 #if NeedFunctionPrototypes
501 Widget,XPoint poly[12]
502 #endif
504 static void draw_hor_tab(
505 #if NeedFunctionPrototypes
506 Widget,Region ,int
507 #endif
509 static void draw_ver_tab(
510 #if NeedFunctionPrototypes
511 Widget,Region ,int
512 #endif
514 static void create_topgc(
515 #if NeedFunctionPrototypes
516 Widget
517 #endif
519 static void create_bottomgc(
520 #if NeedFunctionPrototypes
521 Widget
522 #endif
524 static void create_textgc(
525 #if NeedFunctionPrototypes
526 Widget
527 #endif
529 static void create_fillgc(
530 #if NeedFunctionPrototypes
531 Widget
532 #endif
534 static void create_backgc(
535 #if NeedFunctionPrototypes
536 Widget
537 #endif
539 static void copy_bg(
540 #if NeedFunctionPrototypes
541 Widget,int ,XrmValue *
542 #endif
544 static void set_shape(
545 #if NeedFunctionPrototypes
546 Widget
547 #endif
549 #define done(type, value) do {\
550 if (to->addr != NULL) {\
551 if (to->size < sizeof(type)) {\
552 to->size = sizeof(type);\
553 return False;\
555 *(type*)(to->addr) = (value);\
556 } else {\
557 static type static_val;\
558 static_val = (value);\
559 to->addr = (XtPointer)&static_val;\
561 to->size = sizeof(type);\
562 return True;\
563 }while (0 )
566 static Boolean cvtStringToTabsOrientation(
567 #if NeedFunctionPrototypes
568 Display *,XrmValuePtr ,Cardinal *,XrmValuePtr ,XrmValuePtr ,XtPointer *
569 #endif
571 static Boolean cvtTabsOrientationToString(
572 #if NeedFunctionPrototypes
573 Display *,XrmValuePtr ,Cardinal *,XrmValuePtr ,XrmValuePtr ,XtPointer *
574 #endif
576 /*ARGSUSED*/
577 #if NeedFunctionPrototypes
578 static void compute_tabsizes(Widget self)
579 #else
580 static void compute_tabsizes(self)Widget self;
581 #endif
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;
594 } else {
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 */
613 sum = 0;
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;
622 if (length >= sum)
623 delta = (length - sum)/(n - 1); /* Between tabs */
624 else
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;
630 /*ARGSUSED*/
631 #if NeedFunctionPrototypes
632 static void comp_hor_tab_shape(Widget self,int i,XPoint p[12],int * x0,int * x1,int * midy)
633 #else
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;
635 #endif
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
641 * / \
642 * 3 o o 6
643 * | |
644 * 2 o o 7
645 * 1 / \ 8
646 * 0 o--------o o--------o 9
647 * 11 o---------------------------------------o 10
649 * 11 o---------------------------------------o 10
650 * 0 o--------o o--------o 9
651 * 1 \ / 8
652 * 2 o o 7
653 * | |
654 * 3 o o 6
655 * \ /
656 * 4 o-------------o 5
658 p[0].x = 0;
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;
669 p[11].x = 0;
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;
675 p[3].y = k;
676 p[4].y = 0;
677 p[5].y = 0;
678 p[6].y = 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;
684 } else {
685 p[0].y = shad;
686 p[1].y = shad;
687 p[2].y = shad + k;
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;
692 p[7].y = shad + k;
693 p[8].y = shad;
694 p[9].y = shad;
695 p[10].y = 0;
696 p[11].y = 0;
698 *x0 = p[4].x;
699 *x1 = p[5].x;
700 *midy = (p[1].y + p[4].y)/2;
702 /*ARGSUSED*/
703 #if NeedFunctionPrototypes
704 static void comp_ver_tab_shape(Widget self,int i,XPoint p[12],int * y0,int * y1,int * midx)
705 #else
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;
707 #endif
709 int shad = ((XmTabsWidget)self)->xmManager.shadow_thickness;
710 int k = min(((XmTabsWidget)self)->xmTabs.cornerheight, (((XmTabsWidget)self)->core.width - shad)/2);
712 * 0 o_o 11 11 o_o 0
713 * | | | |
714 * 1 o | | o 1
715 * 3 2/ | | \2 3
716 * o-o | | o-o
717 * / | | \
718 * 4 o | | o 4
719 * | | | |
720 * 5 o | | o 5
721 * \ | | /
722 * o-o | | o-o
723 * 6 7\ | | /7 6
724 * 8 o | | o 8
725 * | | | |
726 * 9 o_o 10 10 o_o 9
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;
732 p[3].x = k;
733 p[4].x = 0;
734 p[5].x = 0;
735 p[6].x = 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;
741 } else {
742 p[0].x = shad;
743 p[1].x = shad;
744 p[2].x = shad + k;
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;
749 p[7].x = shad + k;
750 p[8].x = shad;
751 p[9].x = shad;
752 p[10].x = 0;
753 p[11].x = 0;
755 p[0].y = 0;
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;
766 p[11].y = 0;
767 *y0 = p[4].y;
768 *y1 = p[5].y;
769 *midx = (p[1].x + p[4].x)/2;
771 /*ARGSUSED*/
772 #if NeedFunctionPrototypes
773 static void draw_border(Widget self,XPoint poly[12])
774 #else
775 static void draw_border(self,poly)Widget self;XPoint poly[12];
776 #endif
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);
785 } else {
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);
791 /*ARGSUSED*/
792 #if NeedFunctionPrototypes
793 static void draw_hor_tab(Widget self,Region region,int i)
794 #else
795 static void draw_hor_tab(self,region,i)Widget self;Region region;int i;
796 #endif
798 XPoint p[12];
799 Display *dpy = XtDisplay(self);
800 Window win = XtWindow(self);
801 Region clip;
802 int x0, x1, midy;
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);
816 } else {
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 */
830 else
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);
837 /*ARGSUSED*/
838 #if NeedFunctionPrototypes
839 static void draw_ver_tab(Widget self,Region region,int i)
840 #else
841 static void draw_ver_tab(self,region,i)Widget self;Region region;int i;
842 #endif
844 Display *dpy = XtDisplay(self);
845 Window win = XtWindow(self);
846 XPoint p[12];
847 Region clip;
848 int y0, y1, midx;
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);
862 } else {
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) {
868 int y, align;
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)) {
872 y = (y0 + y1)/2;
873 align = MCENTRE;
874 } else if (i < ((XmTabsWidget)self)->xmTabs.lefttabs) {
875 y = y0 + ((XmTabsWidget)self)->xmTabs.textmargin;
876 align = ((XmTabsWidget)self)->xmTabs.orientation == XfwfLeftTabs ? MRIGHT : MLEFT;
877 } else {
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);
887 /*ARGSUSED*/
888 #if NeedFunctionPrototypes
889 static void create_topgc(Widget self)
890 #else
891 static void create_topgc(self)Widget self;
892 #endif
894 XtGCMask mask = GCForeground | GCLineWidth;
895 XGCValues values;
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)),
901 mask, &values);
903 /*ARGSUSED*/
904 #if NeedFunctionPrototypes
905 static void create_bottomgc(Widget self)
906 #else
907 static void create_bottomgc(self)Widget self;
908 #endif
910 XtGCMask mask = GCForeground | GCLineWidth;
911 XGCValues values;
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)),
917 mask, &values);
919 /*ARGSUSED*/
920 #if NeedFunctionPrototypes
921 static void create_textgc(Widget self)
922 #else
923 static void create_textgc(self)Widget self;
924 #endif
926 XtGCMask mask = GCForeground | GCFont;
927 XGCValues values;
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)),
933 mask, &values);
935 /*ARGSUSED*/
936 #if NeedFunctionPrototypes
937 static void create_fillgc(Widget self)
938 #else
939 static void create_fillgc(self)Widget self;
940 #endif
942 XtGCMask mask = GCForeground;
943 XGCValues values;
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)),
948 mask, &values);
950 /*ARGSUSED*/
951 #if NeedFunctionPrototypes
952 static void create_backgc(Widget self)
953 #else
954 static void create_backgc(self)Widget self;
955 #endif
957 XtGCMask mask = GCForeground;
958 XGCValues values;
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)),
963 mask, &values);
965 /*ARGSUSED*/
966 #if NeedFunctionPrototypes
967 static void copy_bg(Widget self,int offset,XrmValue * value)
968 #else
969 static void copy_bg(self,offset,value)Widget self;int offset;XrmValue * value;
970 #endif
972 value->addr = (XtPointer) &((XmTabsWidget)self)->core.background_pixel;
974 /*ARGSUSED*/
975 #if NeedFunctionPrototypes
976 static void set_shape(Widget self)
977 #else
978 static void set_shape(self)Widget self;
979 #endif
981 int x0, x1, midy, y0, y1, midx, i;
982 Region region, clip;
983 XPoint poly[12];
985 if (! XtIsRealized(self)) return;
987 region = XCreateRegion();
989 switch (((XmTabsWidget)self)->xmTabs.orientation) {
990 case XfwfUpTabs:
991 case XfwfDownTabs:
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);
998 break;
999 case XfwfLeftTabs:
1000 case XfwfRightTabs:
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);
1007 break;
1009 XShapeCombineRegion(XtDisplay(self), XtWindow(self), ShapeBounding,
1010 0, 0, region, ShapeSet);
1011 XDestroyRegion(region);
1014 /*ARGSUSED*/
1015 #if NeedFunctionPrototypes
1016 static Boolean cvtStringToTabsOrientation(Display * display,XrmValuePtr args,Cardinal * num_args,XrmValuePtr from,XrmValuePtr to,XtPointer * converter_data)
1017 #else
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;
1019 #endif
1021 TabsOrientation a = XfwfUpTabs;
1022 char *s = (char*) from->addr;
1023 static struct {
1024 char *name;
1025 TabsOrientation orient;
1026 } strings[] = {
1027 { "up", XfwfUpTabs },
1028 { "uptabs", XfwfUpTabs },
1029 { "down", XfwfDownTabs },
1030 { "downtabs", XfwfDownTabs },
1031 { "left", XfwfLeftTabs },
1032 { "lefttabs", XfwfLeftTabs },
1033 { "right", XfwfRightTabs },
1034 { "righttabs", XfwfRightTabs },
1036 int i;
1038 if (*num_args != 0)
1039 XtAppErrorMsg
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;
1048 break;
1051 if ( i >= XtNumber(strings) )
1052 XtDisplayStringConversionWarning(display, s, "TabsOrientation");
1053 done(TabsOrientation, a);
1055 /*ARGSUSED*/
1056 #if NeedFunctionPrototypes
1057 static Boolean cvtTabsOrientationToString(Display * display,XrmValuePtr args,Cardinal * num_args,XrmValuePtr from,XrmValuePtr to,XtPointer * converter_data)
1058 #else
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;
1060 #endif
1062 TabsOrientation *a = (TabsOrientation*) from->addr;
1064 if (*num_args != 0)
1065 XtAppErrorMsg
1066 (XtDisplayToApplicationContext(display),
1067 "cvtTabsOrientationToString", "wrongParameters", "XtToolkitError",
1068 "TabsOrientation to String conversion needs no arguments",
1069 (String*) NULL, (Cardinal*) NULL);
1070 switch (*a) {
1071 case XfwfUpTabs: done(String, "up");
1072 case XfwfDownTabs: done(String, "down");
1073 case XfwfLeftTabs: done(String, "left");
1074 case XfwfRightTabs: done(String, "right");
1076 XtAppErrorMsg
1077 (XtDisplayToApplicationContext(display),
1078 "cvtTabsOrientationToString", "illParameters", "XtToolkitError",
1079 "TabsOrientation to String conversion got illegal argument",
1080 (String*) NULL, (Cardinal*) NULL);
1081 return TRUE;
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,
1138 NULL
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 */
1160 border_highlight,
1161 border_unhighlight,
1164 WidgetClass xmTabsWidgetClass = (WidgetClass) &xmTabsClassRec;
1165 /*ARGSUSED*/
1166 static void activate(Widget self, XEvent *event, String *params, Cardinal *num_params)
1168 int x0, x1, dummy, i, x, y;
1169 XPoint poly[12];
1171 switch (((XmTabsWidget)self)->xmTabs.orientation) {
1172 case XfwfUpTabs:
1173 case XfwfDownTabs:
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);
1178 return;
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);
1184 return;
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);
1191 return;
1194 break;
1195 case XfwfLeftTabs:
1196 case XfwfRightTabs:
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);
1201 return;
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);
1207 return;
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);
1214 return;
1217 break;
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;
1240 /*ARGSUSED*/
1241 #if NeedFunctionPrototypes
1242 static void class_initialize(void)
1243 #else
1244 static void class_initialize(void)
1245 #endif
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);
1257 /*ARGSUSED*/
1258 #if NeedFunctionPrototypes
1259 static void initialize(Widget request,Widget self,ArgList args,Cardinal * num_args)
1260 #else
1261 static void initialize(request,self,args,num_args)Widget request;Widget self;ArgList args;Cardinal * num_args;
1262 #endif
1264 String *h;
1265 int i;
1267 ((XmTabsWidget)self)->xmManager.traversal_on = FALSE;
1268 ((XmTabsWidget)self)->xmTabs.topgc = NULL;
1269 create_topgc(self);
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);
1293 /*ARGSUSED*/
1294 #if NeedFunctionPrototypes
1295 static Boolean set_values(Widget old,Widget request,Widget self,ArgList args,Cardinal * num_args)
1296 #else
1297 static Boolean set_values(old,request,self,args,num_args)Widget old;Widget request;Widget self;ArgList args;Cardinal * num_args;
1298 #endif
1300 Bool redraw = FALSE, resize_labels = FALSE;
1301 String *h;
1302 int i;
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) {
1307 create_topgc(self);
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);
1313 redraw = TRUE;
1315 if (((XmTabsWidget)self)->xmTabs.tabcolor != ((XmTabsWidget)old)->xmTabs.tabcolor) {
1316 create_fillgc(self);
1317 redraw = TRUE;
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)
1346 redraw = TRUE;
1347 if (resize_labels) {
1348 compute_tabsizes(self);
1349 redraw = TRUE;
1351 return redraw;
1353 /*ARGSUSED*/
1354 #if NeedFunctionPrototypes
1355 static void realize(Widget self,XtValueMask * mask,XSetWindowAttributes * attributes)
1356 #else
1357 static void realize(self,mask,attributes)Widget self;XtValueMask * mask;XSetWindowAttributes * attributes;
1358 #endif
1360 *mask |= CWBitGravity;
1361 attributes->bit_gravity = ForgetGravity;
1362 xmManagerClassRec.core_class.realize(self, mask, attributes);
1363 set_shape(self);
1365 /*ARGSUSED*/
1366 #if NeedFunctionPrototypes
1367 static void resize(Widget self)
1368 #else
1369 static void resize(self)Widget self;
1370 #endif
1372 if (XtIsRealized(self))
1373 XClearArea(XtDisplay(self), XtWindow(self), 0, 0, 0, 0, True);
1374 compute_tabsizes(self);
1375 set_shape(self);
1376 if ( xmManagerClassRec.core_class.resize ) xmManagerClassRec.core_class.resize(self);
1378 /*ARGSUSED*/
1379 #if NeedFunctionPrototypes
1380 static void expose(Widget self,XEvent * event,Region region)
1381 #else
1382 static void expose(self,event,region)Widget self;XEvent * event;Region region;
1383 #endif
1385 int i;
1387 if (! XtIsRealized(self)) return;
1389 switch (((XmTabsWidget)self)->xmTabs.orientation) {
1390 case XfwfUpTabs:
1391 case XfwfDownTabs:
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);
1397 break;
1398 case XfwfLeftTabs:
1399 case XfwfRightTabs:
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);
1405 break;
1407 /* Focus highlight? */
1409 /*ARGSUSED*/
1410 #if NeedFunctionPrototypes
1411 static void border_highlight(void)
1412 #else
1413 static void border_highlight(void)
1414 #endif
1417 /*ARGSUSED*/
1418 #if NeedFunctionPrototypes
1419 static void border_unhighlight(void)
1420 #else
1421 static void border_unhighlight(void)
1422 #endif
1425 /*ARGSUSED*/
1426 #if NeedFunctionPrototypes
1427 static void destroy(Widget self)
1428 #else
1429 static void destroy(self)Widget self;
1430 #endif
1432 int i;
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 */
1501 #ifdef DEBUG
1502 static int debug=1;
1503 #else
1504 static int debug=0;
1505 #endif /*DEBUG*/
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 /* ---------------------------------------------------------------------- */
1517 #ifndef M_PI
1518 #define M_PI 3.14159265358979323846
1519 #endif
1522 /* ---------------------------------------------------------------------- */
1525 /* A structure holding everything needed for a rotated string */
1527 typedef struct rotated_text_item_template {
1528 Pixmap bitmap;
1529 XImage *ximage;
1531 char *text;
1532 char *font_name;
1533 Font fid;
1534 float angle;
1535 int align;
1536 float magnify;
1538 int cols_in;
1539 int rows_in;
1540 int cols_out;
1541 int rows_out;
1543 int nl;
1544 int max_width;
1545 float *corners_x;
1546 float *corners_y;
1548 long int size;
1549 int cached;
1551 struct rotated_text_item_template *next;
1552 } RotatedTextItem;
1554 RotatedTextItem *first_text_item=NULL;
1557 /* ---------------------------------------------------------------------- */
1560 /* A structure holding current magnification and bounding box padding */
1562 static struct style_template {
1563 float magnify;
1564 int bbx_pad;
1565 } style={
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)
1605 char *s;
1607 if(str==NULL)
1608 return NULL;
1610 s=(char *)malloc((unsigned)(strlen(str)+1));
1611 if(s!=NULL)
1612 strcpy(s, str);
1614 return s;
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)
1628 char *ret;
1629 int i, j, stop;
1630 static int start, len;
1631 static char *stext;
1633 if(str2==NULL)
1634 return NULL;
1636 /* initialise if str1 not NULL */
1637 if(str1!=NULL) {
1638 start=0;
1639 stext=str1;
1640 len=strlen(str1);
1643 /* run out of tokens ? */
1644 if(start>=len)
1645 return NULL;
1647 /* loop through characters */
1648 for(i=start; i<len; i++) {
1649 /* loop through delimiters */
1650 stop=0;
1651 for(j=0; j<strlen(str2); j++)
1652 if(stext[i]==str2[j])
1653 stop=1;
1655 if(stop)
1656 break;
1659 stext[i]='\0';
1661 ret=stext+start;
1663 start=i+1;
1665 return ret;
1669 /* ---------------------------------------------------------------------- */
1672 /**************************************************************************/
1673 /* Return version/copyright information */
1674 /**************************************************************************/
1675 static
1676 float XRotVersion(char *str, int n)
1678 if(str!=NULL)
1679 strncpy(str, XV_COPYRIGHT, n);
1680 return XV_VERSION;
1684 /* ---------------------------------------------------------------------- */
1687 /**************************************************************************/
1688 /* Set the font magnification factor for all subsequent operations */
1689 /**************************************************************************/
1690 static
1691 void XRotSetMagnification(float m)
1693 if(m>0.)
1694 style.magnify=m;
1698 /* ---------------------------------------------------------------------- */
1701 /**************************************************************************/
1702 /* Set the padding used when calculating bounding boxes */
1703 /**************************************************************************/
1704 static
1705 void XRotSetBoundingBoxPad(int p)
1707 if(p>=0)
1708 style.bbx_pad=p;
1712 /* ---------------------------------------------------------------------- */
1715 /**************************************************************************/
1716 /* Create an XImage structure and allocate memory for it */
1717 /**************************************************************************/
1719 static XImage *MakeXImage(Display *dpy, int w, int h)
1721 XImage *I;
1722 char *data;
1724 /* reserve memory for image */
1725 data=(char *)calloc((unsigned)(((w-1)/8+1)*h), 1);
1726 if(data==NULL)
1727 return NULL;
1729 /* create the XImage */
1730 I=XCreateImage(dpy, DefaultVisual(dpy, DefaultScreen(dpy)), 1, XYBitmap,
1731 0, data, w, h, 8, 0);
1732 if(I==NULL)
1733 return NULL;
1735 I->byte_order=I->bitmap_bit_order=MSBFirst;
1736 return I;
1740 /* ---------------------------------------------------------------------- */
1743 /**************************************************************************/
1744 /* A front end to XRotPaintAlignedString: */
1745 /* -no alignment, no background */
1746 /**************************************************************************/
1747 static
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 /**************************************************************************/
1762 static
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 /**************************************************************************/
1777 static
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 /**************************************************************************/
1792 static
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)
1809 int i;
1810 GC my_gc;
1811 int xp, yp;
1812 float hot_x, hot_y;
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 */
1819 if(text==NULL)
1820 return 0;
1822 if(strlen(text)==0)
1823 return 0;
1825 /* manipulate angle to 0<=angle<360 degrees */
1826 while(angle<0)
1827 angle+=360;
1829 while(angle>=360)
1830 angle-=360;
1832 angle*=M_PI/180;
1834 /* horizontal text made easy */
1835 if(angle==0. && style.magnify==1.)
1836 return(XRotDrawHorizontalString(dpy, font, drawable, gc, x, y,
1837 text, align, bg));
1839 /* get a rotated bitmap */
1840 item=XRotRetrieveFromCache(dpy, font, angle, text, align);
1841 if(item==NULL)
1842 return NULL;
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? */
1852 /* y position */
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)
1856 hot_y=0;
1857 else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
1858 hot_y = -(float)item->rows_in/2*style.magnify;
1859 else
1860 hot_y = -((float)item->rows_in/2-(float)font->descent)*style.magnify;
1862 /* x position */
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)
1866 hot_x=0;
1867 else
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 */
1879 if(bg) {
1880 GC depth_one_gc;
1881 XPoint *xpoints;
1882 Pixmap empty_stipple;
1884 /* reserve space for XPoints */
1885 xpoints=(XPoint *)malloc((unsigned)(4*item->nl*sizeof(XPoint)));
1886 if(!xpoints)
1887 return 1;
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,
1910 CoordModeOrigin);
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 */
1926 #ifndef X11R3
1928 GC depth_one_gc;
1929 XGCValues values;
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,
1936 &values)) {
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);
1957 /* create a GC */
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);
1979 /* invert text */
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;
2003 #endif /*X11R3*/
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 */
2024 if(!item->cached)
2025 XRotFreeTextItem(dpy,item);
2027 /* we got to the end OK! */
2028 return 0;
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)
2041 GC my_gc;
2042 int nl=1, i;
2043 int height;
2044 int xp, yp;
2045 char *str1, *str2, *str3;
2046 char *str2_a="\0", *str2_b="\n\0";
2047 int dir, asc, desc;
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);
2054 XCopyGC(dpy, gc,
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 */
2061 if(align!=NONE)
2062 for(i=0; i<strlen(text)-1; i++)
2063 if(text[i]=='\n')
2064 nl++;
2066 /* ignore newline characters if not doing alignment */
2067 if(align==NONE)
2068 str2=str2_a;
2069 else
2070 str2=str2_b;
2072 /* overall font height */
2073 height=font->ascent+font->descent;
2075 /* y position */
2076 if(align==TLEFT || align==TCENTRE || align==TRIGHT)
2077 yp=y+font->ascent;
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;
2082 else
2083 yp=y;
2085 str1=my_strdup(text);
2086 if(str1==NULL)
2087 return 1;
2089 str3=my_strtok(str1, str2);
2091 /* loop through each section in the string */
2092 do {
2093 XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
2094 &overall);
2096 /* where to draw section in x ? */
2097 if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
2098 xp=x;
2099 else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
2100 xp=x-overall.rbearing/2;
2101 else
2102 xp=x-overall.rbearing;
2104 /* draw string onto bitmap */
2105 if(!bg)
2106 XDrawString(dpy, drawable, my_gc, xp, yp, str3, strlen(str3));
2107 else
2108 XDrawImageString(dpy, drawable, my_gc, xp, yp, str3, strlen(str3));
2110 /* move to next line */
2111 yp+=height;
2113 str3=my_strtok((char *)NULL, str2);
2115 while(str3!=NULL);
2117 free(str1);
2118 XFreeGC(dpy, my_gc);
2120 return 0;
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)
2134 Font fid;
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);
2144 fid=0;
2146 #ifdef CACHE_FID
2147 /* otherwise rely (unreliably?) on font ID */
2148 else {
2149 DEBUG_PRINT1("can't get fontname, caching FID\n");
2150 font_name=NULL;
2151 fid=font->fid;
2153 #else
2154 /* not allowed to cache font ID's */
2155 else {
2156 DEBUG_PRINT1("can't get fontname, can't cache\n");
2157 font_name=NULL;
2158 fid=0;
2160 #endif /*CACHE_FID*/
2162 /* look for a match in cache */
2164 /* matching formula:
2165 identical text;
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 &&
2176 (i1->nl==1 ||
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) {
2183 item=i1;
2184 DEBUG_PRINT1("Matched against font names\n");
2186 else
2187 i1=i1->next;
2189 #ifdef CACHE_FID
2190 else if(font_name==NULL && i1->font_name==NULL) {
2191 if(fid==i1->fid) {
2192 item=i1;
2193 DEBUG_PRINT1("Matched against FID's\n");
2195 else
2196 i1=i1->next;
2198 #endif /*CACHE_FID*/
2199 else
2200 i1=i1->next;
2202 else
2203 i1=i1->next;
2206 if(item)
2207 DEBUG_PRINT1("**\nFound target in cache.\n");
2208 if(!item)
2209 DEBUG_PRINT1("**\nNo match in cache.\n");
2211 /* no match */
2212 if(!item) {
2213 /* create new item */
2214 item=XRotCreateTextItem(dpy, font, angle, text, align);
2215 if(!item)
2216 return NULL;
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);
2224 item->fid=0;
2226 else {
2227 item->font_name=NULL;
2228 item->fid=fid;
2231 item->angle=angle;
2232 item->align=align;
2233 item->magnify=style.magnify;
2235 /* cache it */
2236 XRotAddToLinkedList(dpy, item);
2239 if(font_name)
2240 XFree(font_name);
2242 /* if XImage is cached, need to recreate the bitmap */
2244 #ifdef CACHE_XIMAGES
2246 GC depth_one_gc;
2248 /* create bitmap to hold rotated text */
2249 item->bitmap=XCreatePixmap(dpy, DefaultRootWindow(dpy),
2250 item->cols_out, item->rows_out, 1);
2252 /* depth one gc */
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*/
2265 return item;
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;
2279 Pixmap canvas;
2280 GC font_gc;
2281 XImage *I_in;
2282 register int i, j;
2283 char *str1, *str2, *str3;
2284 char *str2_a="\0", *str2_b="\n\0";
2285 int height;
2286 int byte_w_in, byte_w_out;
2287 int xp, yp;
2288 float sin_angle, cos_angle;
2289 int it, jt;
2290 float di, dj;
2291 int ic=0;
2292 float xl, xr, xinc;
2293 int byte_out;
2294 int dir, asc, desc;
2295 XCharStruct overall;
2296 int old_cols_in=0, old_rows_in=0;
2298 /* allocate memory */
2299 item=(RotatedTextItem *)malloc((unsigned)sizeof(RotatedTextItem));
2300 if(!item)
2301 return NULL;
2303 /* count number of sections in string */
2304 item->nl=1;
2305 if(align!=NONE)
2306 for(i=0; i<strlen(text)-1; i++)
2307 if(text[i]=='\n')
2308 item->nl++;
2310 /* ignore newline characters if not doing alignment */
2311 if(align==NONE)
2312 str2=str2_a;
2313 else
2314 str2=str2_b;
2316 /* find width of longest section */
2317 str1=my_strdup(text);
2318 if(str1==NULL)
2319 return NULL;
2321 str3=my_strtok(str1, str2);
2323 XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
2324 &overall);
2326 item->max_width=overall.rbearing;
2328 /* loop through each section */
2329 do {
2330 str3=my_strtok((char *)NULL, str2);
2332 if(str3!=NULL) {
2333 XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
2334 &overall);
2336 if(overall.rbearing>item->max_width)
2337 item->max_width=overall.rbearing;
2340 while(str3!=NULL);
2342 free(str1);
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 */
2371 item->corners_x=
2372 (float *)malloc((unsigned)(4*item->nl*sizeof(float)));
2373 if(!item->corners_x)
2374 return NULL;
2376 item->corners_y=
2377 (float *)malloc((unsigned)(4*item->nl*sizeof(float)));
2378 if(!item->corners_y)
2379 return NULL;
2381 /* draw text horizontally */
2383 /* start at top of bitmap */
2384 yp=font->ascent;
2386 str1=my_strdup(text);
2387 if(str1==NULL)
2388 return NULL;
2390 str3=my_strtok(str1, str2);
2392 /* loop through each section in the string */
2393 do {
2394 XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
2395 &overall);
2397 /* where to draw section in x ? */
2398 if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
2399 xp=0;
2400 else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
2401 xp=(item->max_width-overall.rbearing)/2;
2402 else
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)
2411 *style.magnify;
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];
2421 ic+=2;
2423 /* move to next line */
2424 yp+=height;
2426 str3=my_strtok((char *)NULL, str2);
2428 while(str3!=NULL);
2430 free(str1);
2432 /* create image to hold horizontal text */
2433 I_in=MakeXImage(dpy, item->cols_in, item->rows_in);
2434 if(I_in==NULL)
2435 return NULL;
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)
2460 item->cols_out++;
2462 if(item->rows_out%2==0)
2463 item->rows_out++;
2465 /* create image to hold rotated text */
2466 item->ximage=MakeXImage(dpy, item->cols_out, item->rows_out);
2467 if(item->ximage==NULL)
2468 return 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) {
2482 xl=0;
2483 xr=(float)item->cols_out;
2484 xinc=0;
2486 else if(angle<M_PI) {
2487 xl=(float)item->cols_out/2+
2488 (dj-(float)item->rows_in/(2*cos_angle))/
2489 tan(angle)-2;
2490 xr=(float)item->cols_out/2+
2491 (dj+(float)item->rows_in/(2*cos_angle))/
2492 tan(angle)+2;
2493 xinc=1./tan(angle);
2495 else {
2496 xl=(float)item->cols_out/2+
2497 (dj+(float)item->rows_in/(2*cos_angle))/
2498 tan(angle)-2;
2499 xr=(float)item->cols_out/2+
2500 (dj-(float)item->rows_in/(2*cos_angle))/
2501 tan(angle)+2;
2503 xinc=1./tan(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;
2526 di+=1;
2528 dj+=1;
2529 xl+=xinc;
2530 xr+=xinc;
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);
2557 return item;
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;
2583 #else
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);
2593 else
2594 item->size+=sizeof(Font);
2596 #endif /*CACHE_BITMAPS */
2598 #ifdef DEBUG
2599 /* count number of items in cache, for debugging */
2601 int i=0;
2603 while(i1) {
2604 i++;
2605 i1=i1->next;
2607 DEBUG_PRINT2("Cache has %d items.\n", i);
2608 i1=first_text_item;
2610 #endif
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");
2618 item->cached=0;
2619 return;
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);
2631 #ifdef CACHE_FID
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;
2639 i2=i1->next;
2641 /* free resources used by the unlucky item */
2642 XRotFreeTextItem(dpy, i1);
2644 /* remove it from linked list */
2645 first_text_item=i2;
2646 i1=i2;
2649 /* add new item to end of linked list */
2650 if(first_text_item==NULL) {
2651 item->next=NULL;
2652 first_text_item=item;
2653 last=item;
2655 else {
2656 item->next=NULL;
2657 last->next=item;
2658 last=item;
2661 /* new cache size */
2662 current_size+=item->size;
2664 item->cached=1;
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)
2679 free(item->text);
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);
2689 #else
2690 XDestroyImage(item->ximage);
2691 #endif /* CACHE_BITMAPS */
2693 free((char *)item);
2697 /* ---------------------------------------------------------------------- */
2700 /**************************************************************************/
2701 /* Magnify an XImage using bilinear interpolation */
2702 /**************************************************************************/
2704 static XImage *XRotMagnifyImage(Display *dpy, XImage *ximage)
2706 int i, j;
2707 float x, y;
2708 float u,t;
2709 XImage *I_out;
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;
2715 float mag_inv;
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);
2727 if(I_out==NULL)
2728 return NULL;
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;
2734 /* for speed */
2735 mag_inv=1./style.magnify;
2737 y=0.;
2739 /* loop over magnified image */
2740 for(j2=0; j2<rows_out; j2++) {
2741 x=0;
2742 j=y;
2744 for(i2=0; i2<cols_out; i2++) {
2745 i=x;
2747 /* bilinear interpolation - where are we on bitmap ? */
2748 /* right edge */
2749 if(i==cols_in-1 && j!=rows_in-1) {
2750 t=0;
2751 u=y-(float)j;
2753 z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
2754 z2=z1;
2755 z3=(ximage->data[(j+1)*byte_width_in+i/8] & 128>>(i%8))>0;
2756 z4=z3;
2758 /* top edge */
2759 else if(i!=cols_in-1 && j==rows_in-1) {
2760 t=x-(float)i;
2761 u=0;
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;
2765 z3=z2;
2766 z4=z1;
2768 /* top right corner */
2769 else if(i==cols_in-1 && j==rows_in-1) {
2770 u=0;
2771 t=0;
2773 z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
2774 z2=z1;
2775 z3=z1;
2776 z4=z1;
2778 /* somewhere `safe' */
2779 else {
2780 t=x-(float)i;
2781 u=y-(float)j;
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] &
2786 128>>((i+1)%8))>0;
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;
2794 x+=mag_inv;
2796 y+=mag_inv;
2799 /* destroy original */
2800 XDestroyImage(ximage);
2802 /* return big image */
2803 return I_out;
2808 /* ---------------------------------------------------------------------- */
2811 /**************************************************************************/
2812 /* Calculate the bounding box some text will have when painted */
2813 /**************************************************************************/
2814 static
2815 XPoint *XRotTextExtents(Display *dpy, XFontStruct *font, float angle, int x, int y, char *text, int align)
2817 register int i;
2818 char *str1, *str2, *str3;
2819 char *str2_a="\0", *str2_b="\n\0";
2820 int height;
2821 float sin_angle, cos_angle;
2822 int nl, max_width;
2823 int cols_in, rows_in;
2824 float hot_x, hot_y;
2825 XPoint *xp_in, *xp_out;
2826 int dir, asc, desc;
2827 XCharStruct overall;
2829 /* manipulate angle to 0<=angle<360 degrees */
2830 while(angle<0)
2831 angle+=360;
2833 while(angle>360)
2834 angle-=360;
2836 angle*=M_PI/180;
2838 /* count number of sections in string */
2839 nl=1;
2840 if(align!=NONE)
2841 for(i=0; i<strlen(text)-1; i++)
2842 if(text[i]=='\n')
2843 nl++;
2845 /* ignore newline characters if not doing alignment */
2846 if(align==NONE)
2847 str2=str2_a;
2848 else
2849 str2=str2_b;
2851 /* find width of longest section */
2852 str1=my_strdup(text);
2853 if(str1==NULL)
2854 return NULL;
2856 str3=my_strtok(str1, str2);
2858 XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
2859 &overall);
2861 max_width=overall.rbearing;
2863 /* loop through each section */
2864 do {
2865 str3=my_strtok((char *)NULL, str2);
2867 if(str3!=NULL) {
2868 XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
2869 &overall);
2871 if(overall.rbearing>max_width)
2872 max_width=overall.rbearing;
2875 while(str3!=NULL);
2877 free(str1);
2879 /* overall font height */
2880 height=font->ascent+font->descent;
2882 /* dimensions horizontal text will have */
2883 cols_in=max_width;
2884 rows_in=nl*height;
2886 /* pre-calculate sin and cos */
2887 sin_angle=sin(angle);
2888 cos_angle=cos(angle);
2890 /* y position */
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)
2894 hot_y=0;
2895 else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
2896 hot_y = -(float)rows_in/2*style.magnify;
2897 else
2898 hot_y = -((float)rows_in/2-(float)font->descent)*style.magnify;
2900 /* x position */
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)
2904 hot_x=0;
2905 else
2906 hot_x=(float)max_width/2*style.magnify;
2908 /* reserve space for XPoints */
2909 xp_in=(XPoint *)malloc((unsigned)(5*sizeof(XPoint)));
2910 if(!xp_in)
2911 return NULL;
2913 xp_out=(XPoint *)malloc((unsigned)(5*sizeof(XPoint)));
2914 if(!xp_out)
2915 return NULL;
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);
2939 return xp_out;
2944 /* ***********************************************************************
2945 * Conversion routines for the X resource manager
2946 * ***********************************************************************
2949 #if defined(__STDC__)
2950 static
2951 Boolean strtocard( Display *dsp,
2952 XrmValue *args,
2953 Cardinal *num_args,
2954 XrmValue *from,
2955 XrmValue *to,
2956 XtPointer *unused
2958 #else
2959 static
2960 Boolean strtocard( dsp, args, num_args, from, to, unused )
2961 Display *dsp;
2962 XrmValue *args;
2963 Cardinal *num_args;
2964 XrmValue *from;
2965 XrmValue *to;
2966 XtPointer *unused;
2967 #endif
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 );
2977 return True;
2981 #define done_bert(type, value) \
2982 do {\
2983 if (to->addr != NULL) {\
2984 if (to->size < sizeof(type)) {\
2985 to->size = sizeof(type);\
2986 return False;\
2988 *(type*)(to->addr) = (value);\
2989 } else {\
2990 static type static_val;\
2991 static_val = (value);\
2992 to->addr = (XtPointer)&static_val;\
2994 to->size = sizeof(type);\
2995 return True;\
2996 } while (0)
2997 static
2998 Boolean cvtStringToStringArray(Display *display, XrmValuePtr args, Cardinal *num_args, XrmValuePtr from, XrmValuePtr to, XtPointer *converter_data)
3000 String t, s;
3001 StringArray a = NULL;
3002 Cardinal i;
3003 char delim;
3005 if (*num_args != 0)
3006 XtAppErrorMsg(XtDisplayToApplicationContext(display),
3007 "cvtStringToStringArray", "wrongParameters",
3008 "XtToolkitError",
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);
3014 i = 0;
3015 while (s && *s) {
3016 t = strchr(s, delim);
3017 if (t) *t = '\0';
3018 a = (StringArray) XtRealloc((String) a, (i + 1) * sizeof(*a));
3019 a[i] = s;
3020 i++;
3021 s = t ? t + 1 : NULL;
3023 a = (StringArray) XtRealloc((String) a, (i + 1) * sizeof(*a));
3024 a[i] = NULL;
3025 done_bert(StringArray, a);
3029 /* ***********************************************************************
3030 * A driver for the above in the flavor of the xt utilities module
3031 * ***********************************************************************
3034 #define TABHT 25
3036 typedef struct tab_data {
3037 Widget form;
3038 int cur,
3039 num_tabs;
3040 void (*activate_func)();
3041 } *TabData;
3044 #if defined(__STDC__)
3045 static void handle_click( Widget w, TabData td, XtPointer call_data )
3046 #else
3047 static void handle_click(w, td, call_data)
3048 Widget w;
3049 TabData td;
3050 XtPointer call_data;
3051 #endif
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;
3060 td->cur += tab;
3062 /* Change tabs. We must manually inform the UI which tab is current */
3063 XtVaSetValues( w,
3064 XtNlefttabs, td->cur,
3065 XtNrighttabs, td->num_tabs - td->cur - 1,
3066 NULL
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,
3079 Widget parent,
3080 String tab_labels,
3081 int num_tabs,
3082 void (*activate_func)()
3084 #else
3085 Widget __vi_CreateTabbedFolder( name, parent, tab_labels, num_tabs, activate_func )
3086 String name;
3087 String tab_labels;
3088 Widget parent;
3089 int num_tabs;
3090 void (*activate_func)();
3091 #endif
3093 Widget tabs;
3094 TabData td = (TabData) malloc( sizeof(struct tab_data) );
3095 int i;
3097 XtAppSetTypeConverter( XtDisplayToApplicationContext(XtDisplay(parent)),
3098 XtRString,
3099 XtRCardinal,
3100 strtocard,
3101 NULL,
3103 XtCacheNone,
3104 NULL
3107 /* init our internal structure */
3108 td->cur = 0;
3109 td->num_tabs = num_tabs;
3110 td->activate_func = activate_func;
3112 /* tabs go on the top */
3113 tabs = XtVaCreateManagedWidget( "tabs",
3114 xmTabsWidgetClass,
3115 parent,
3116 XtNlefttabs, 0,
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,
3128 XtRString,
3129 tab_labels,
3130 strlen(tab_labels) + 1,
3131 NULL
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",
3143 xmFormWidgetClass,
3144 parent,
3145 XmNtopAttachment, XmATTACH_WIDGET,
3146 XmNtopWidget, tabs,
3147 XmNleftAttachment, XmATTACH_FORM,
3148 XmNbottomAttachment, XmATTACH_FORM,
3149 XmNrightAttachment, XmATTACH_FORM,
3150 NULL
3153 /* done */
3154 return td->form;