Final part of yesterday's split input fixes.
[nvi.git] / motif_l / xtabbed.c
blob83b42ea989bd035b2403e35d984aa666661cc23a
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();
99 static void XRotSetMagnification();
100 static void XRotSetBoundingBoxPad();
101 static int XRotDrawString();
102 static int XRotDrawImageString();
103 static int XRotDrawAlignedString();
104 static int XRotDrawAlignedImageString();
105 static XPoint *XRotTextExtents();
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.4 $ of $Date: 1996/12/17 19:11:41 $)
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.4 $ of $Date: 1996/12/17 19:11:41 $)
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(self,event,params,num_params)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(class)
1222 WidgetClass class;
1224 XmTabsWidgetClass c = (XmTabsWidgetClass) class;
1225 XmTabsWidgetClass super;
1226 static CompositeClassExtensionRec extension_rec = {
1227 NULL, NULLQUARK, XtCompositeExtensionVersion,
1228 sizeof(CompositeClassExtensionRec), True};
1229 CompositeClassExtensionRec *ext;
1230 ext = (XtPointer)XtMalloc(sizeof(*ext));
1231 *ext = extension_rec;
1232 ext->next_extension = c->composite_class.extension;
1233 c->composite_class.extension = ext;
1234 if (class == xmTabsWidgetClass) return;
1235 super = (XmTabsWidgetClass)class->core_class.superclass;
1236 if (c->xmTabs_class.border_highlight == XtInherit_border_highlight)
1237 c->xmTabs_class.border_highlight = super->xmTabs_class.border_highlight;
1238 if (c->xmTabs_class.border_unhighlight == XtInherit_border_unhighlight)
1239 c->xmTabs_class.border_unhighlight = super->xmTabs_class.border_unhighlight;
1241 /*ARGSUSED*/
1242 #if NeedFunctionPrototypes
1243 static void class_initialize(void)
1244 #else
1245 static void class_initialize()
1246 #endif
1248 XtSetTypeConverter(XtRString, "StringArray",
1249 cvtStringToStringArray,
1250 NULL, 0, XtCacheNone, NULL);
1251 XtSetTypeConverter(XtRString, "TabsOrientation",
1252 cvtStringToTabsOrientation,
1253 NULL, 0, XtCacheNone, NULL);
1254 XtSetTypeConverter("TabsOrientation", XtRString,
1255 cvtTabsOrientationToString,
1256 NULL, 0, XtCacheNone, NULL);
1258 /*ARGSUSED*/
1259 #if NeedFunctionPrototypes
1260 static void initialize(Widget request,Widget self,ArgList args,Cardinal * num_args)
1261 #else
1262 static void initialize(request,self,args,num_args)Widget request;Widget self;ArgList args;Cardinal * num_args;
1263 #endif
1265 String *h;
1266 int i;
1268 ((XmTabsWidget)self)->xmManager.traversal_on = FALSE;
1269 ((XmTabsWidget)self)->xmTabs.topgc = NULL;
1270 create_topgc(self);
1271 ((XmTabsWidget)self)->xmTabs.bottomgc = NULL;
1272 create_bottomgc(self);
1273 ((XmTabsWidget)self)->xmTabs.textgc = NULL;
1274 create_textgc(self);
1275 ((XmTabsWidget)self)->xmTabs.fillgc = NULL;
1276 create_fillgc(self);
1277 ((XmTabsWidget)self)->xmTabs.backgc = NULL;
1278 create_backgc(self);
1279 if (((XmTabsWidget)self)->xmTabs.labels) {
1280 h = (String*) XtMalloc((((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs + 1) * sizeof(*h));
1281 for (i = ((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs; i >= 0; i--)
1282 h[i] = XtNewString(((XmTabsWidget)self)->xmTabs.labels[i]);
1283 ((XmTabsWidget)self)->xmTabs.labels = h;
1285 if (((XmTabsWidget)self)->xmTabs.tabWidthPercentage < 0 || ((XmTabsWidget)self)->xmTabs.tabWidthPercentage > 100) {
1286 XtAppWarning(XtWidgetToApplicationContext(self),
1287 "tabWidthPercentage out of range; reset to 50");
1288 ((XmTabsWidget)self)->xmTabs.tabWidthPercentage = 50;
1290 ((XmTabsWidget)self)->xmTabs.offsets = NULL;
1291 ((XmTabsWidget)self)->xmTabs.tabwidths = NULL;
1292 compute_tabsizes(self);
1294 /*ARGSUSED*/
1295 #if NeedFunctionPrototypes
1296 static Boolean set_values(Widget old,Widget request,Widget self,ArgList args,Cardinal * num_args)
1297 #else
1298 static Boolean set_values(old,request,self,args,num_args)Widget old;Widget request;Widget self;ArgList args;Cardinal * num_args;
1299 #endif
1301 Bool redraw = FALSE, resize_labels = FALSE;
1302 String *h;
1303 int i;
1305 if (((XmTabsWidget)self)->core.background_pixel != ((XmTabsWidget)old)->core.background_pixel
1306 || ((XmTabsWidget)self)->core.background_pixmap != ((XmTabsWidget)old)->core.background_pixmap
1307 || ((XmTabsWidget)self)->xmManager.shadow_thickness != ((XmTabsWidget)old)->xmManager.shadow_thickness) {
1308 create_topgc(self);
1309 create_bottomgc(self);
1310 create_backgc(self);
1312 if (((XmTabsWidget)self)->xmManager.foreground != ((XmTabsWidget)old)->xmManager.foreground || ((XmTabsWidget)self)->xmTabs.font != ((XmTabsWidget)old)->xmTabs.font) {
1313 create_textgc(self);
1314 redraw = TRUE;
1316 if (((XmTabsWidget)self)->xmTabs.tabcolor != ((XmTabsWidget)old)->xmTabs.tabcolor) {
1317 create_fillgc(self);
1318 redraw = TRUE;
1320 if ((((XmTabsWidget)self)->xmTabs.textmargin != ((XmTabsWidget)old)->xmTabs.textmargin && ((XmTabsWidget)self)->xmTabs.tabWidthPercentage == 0)
1321 || ((XmTabsWidget)self)->xmTabs.cornerwidth != ((XmTabsWidget)old)->xmTabs.cornerwidth
1322 || ((XmTabsWidget)self)->xmTabs.cornerheight != ((XmTabsWidget)old)->xmTabs.cornerheight) {
1323 resize_labels = TRUE;
1325 if (((XmTabsWidget)self)->xmTabs.labels != ((XmTabsWidget)old)->xmTabs.labels) {
1326 if (((XmTabsWidget)self)->xmTabs.labels) {
1327 h = (String*) XtMalloc((((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs + 1) * sizeof(*h));
1328 for (i = ((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs; i >= 0; i--)
1329 h[i] = XtNewString(((XmTabsWidget)self)->xmTabs.labels[i]);
1330 ((XmTabsWidget)self)->xmTabs.labels = h;
1332 if (((XmTabsWidget)old)->xmTabs.labels) {
1333 for (i = ((XmTabsWidget)old)->xmTabs.lefttabs + ((XmTabsWidget)old)->xmTabs.righttabs; i >= 0; i--)
1334 XtFree(((XmTabsWidget)old)->xmTabs.labels[i]);
1335 XtFree((XtPointer) ((XmTabsWidget)old)->xmTabs.labels);
1337 resize_labels = TRUE;
1339 if (((XmTabsWidget)self)->xmTabs.tabWidthPercentage < 0 || ((XmTabsWidget)self)->xmTabs.tabWidthPercentage > 100) {
1340 XtAppWarning(XtWidgetToApplicationContext(self),
1341 "tabWidthPercentage out of range; reset to 50");
1342 ((XmTabsWidget)self)->xmTabs.tabWidthPercentage = 50;
1344 if (((XmTabsWidget)old)->xmTabs.tabWidthPercentage != ((XmTabsWidget)self)->xmTabs.tabWidthPercentage)
1345 resize_labels = TRUE;
1346 if (((XmTabsWidget)self)->xmTabs.lefttabs != ((XmTabsWidget)old)->xmTabs.lefttabs || ((XmTabsWidget)self)->xmTabs.righttabs != ((XmTabsWidget)old)->xmTabs.righttabs)
1347 redraw = TRUE;
1348 if (resize_labels) {
1349 compute_tabsizes(self);
1350 redraw = TRUE;
1352 return redraw;
1354 /*ARGSUSED*/
1355 #if NeedFunctionPrototypes
1356 static void realize(Widget self,XtValueMask * mask,XSetWindowAttributes * attributes)
1357 #else
1358 static void realize(self,mask,attributes)Widget self;XtValueMask * mask;XSetWindowAttributes * attributes;
1359 #endif
1361 *mask |= CWBitGravity;
1362 attributes->bit_gravity = ForgetGravity;
1363 xmManagerClassRec.core_class.realize(self, mask, attributes);
1364 set_shape(self);
1366 /*ARGSUSED*/
1367 #if NeedFunctionPrototypes
1368 static void resize(Widget self)
1369 #else
1370 static void resize(self)Widget self;
1371 #endif
1373 if (XtIsRealized(self))
1374 XClearArea(XtDisplay(self), XtWindow(self), 0, 0, 0, 0, True);
1375 compute_tabsizes(self);
1376 set_shape(self);
1377 if ( xmManagerClassRec.core_class.resize ) xmManagerClassRec.core_class.resize(self);
1379 /*ARGSUSED*/
1380 #if NeedFunctionPrototypes
1381 static void expose(Widget self,XEvent * event,Region region)
1382 #else
1383 static void expose(self,event,region)Widget self;XEvent * event;Region region;
1384 #endif
1386 int i;
1388 if (! XtIsRealized(self)) return;
1390 switch (((XmTabsWidget)self)->xmTabs.orientation) {
1391 case XfwfUpTabs:
1392 case XfwfDownTabs:
1393 for (i = 0; i < ((XmTabsWidget)self)->xmTabs.lefttabs; i++)
1394 draw_hor_tab(self, region, i);
1395 for (i = ((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs; i > ((XmTabsWidget)self)->xmTabs.lefttabs; i--)
1396 draw_hor_tab(self, region, i);
1397 draw_hor_tab(self, region, ((XmTabsWidget)self)->xmTabs.lefttabs);
1398 break;
1399 case XfwfLeftTabs:
1400 case XfwfRightTabs:
1401 for (i = 0; i < ((XmTabsWidget)self)->xmTabs.lefttabs; i++)
1402 draw_ver_tab(self, region, i);
1403 for (i = ((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs; i > ((XmTabsWidget)self)->xmTabs.lefttabs; i--)
1404 draw_ver_tab(self, region, i);
1405 draw_ver_tab(self, region, ((XmTabsWidget)self)->xmTabs.lefttabs);
1406 break;
1408 /* Focus highlight? */
1410 /*ARGSUSED*/
1411 #if NeedFunctionPrototypes
1412 static void border_highlight(void)
1413 #else
1414 static void border_highlight()
1415 #endif
1418 /*ARGSUSED*/
1419 #if NeedFunctionPrototypes
1420 static void border_unhighlight(void)
1421 #else
1422 static void border_unhighlight()
1423 #endif
1426 /*ARGSUSED*/
1427 #if NeedFunctionPrototypes
1428 static void destroy(Widget self)
1429 #else
1430 static void destroy(self)Widget self;
1431 #endif
1433 int i;
1435 if (((XmTabsWidget)self)->xmTabs.labels) {
1436 for (i = ((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs; i >= 0; i--)
1437 XtFree(((XmTabsWidget)self)->xmTabs.labels[i]);
1438 XtFree((XtPointer) ((XmTabsWidget)self)->xmTabs.labels);
1440 if (((XmTabsWidget)self)->xmTabs.offsets)
1441 XtFree((XtPointer) ((XmTabsWidget)self)->xmTabs.offsets);
1442 if (((XmTabsWidget)self)->xmTabs.tabwidths)
1443 XtFree((XtPointer) ((XmTabsWidget)self)->xmTabs.tabwidths);
1447 /* ***********************************************************************
1448 * Routines for drawing rotated text
1449 * ***********************************************************************
1452 /* xvertext 5.0, Copyright (c) 1993 Alan Richardson (mppa3@uk.ac.sussex.syma)
1454 * Permission to use, copy, modify, and distribute this software and its
1455 * documentation for any purpose and without fee is hereby granted, provided
1456 * that the above copyright notice appear in all copies and that both the
1457 * copyright notice and this permission notice appear in supporting
1458 * documentation. All work developed as a consequence of the use of
1459 * this program should duly acknowledge such use. No representations are
1460 * made about the suitability of this software for any purpose. It is
1461 * provided "as is" without express or implied warranty.
1463 * 8 Jun '95: [Bert Bos] added GCClipXOrigin|GCClipYOrigin|GCClipMask
1464 * when calling XCopyGC()
1467 /* ********************************************************************** */
1470 /* BETTER: xvertext now does rotation at any angle!!
1472 * BEWARE: function arguments have CHANGED since version 2.0!!
1475 /* ********************************************************************** */
1479 /* ---------------------------------------------------------------------- */
1482 /* Make sure cache size is set */
1484 #ifndef CACHE_SIZE_LIMIT
1485 #define CACHE_SIZE_LIMIT 0
1486 #endif /*CACHE_SIZE_LIMIT */
1488 /* Make sure a cache method is specified */
1490 #ifndef CACHE_XIMAGES
1491 #ifndef CACHE_BITMAPS
1492 #define CACHE_BITMAPS
1493 #endif /*CACHE_BITMAPS*/
1494 #endif /*CACHE_XIMAGES*/
1497 /* ---------------------------------------------------------------------- */
1500 /* Debugging macros */
1502 #ifdef DEBUG
1503 static int debug=1;
1504 #else
1505 static int debug=0;
1506 #endif /*DEBUG*/
1508 #define DEBUG_PRINT1(a) if (debug) printf (a)
1509 #define DEBUG_PRINT2(a, b) if (debug) printf (a, b)
1510 #define DEBUG_PRINT3(a, b, c) if (debug) printf (a, b, c)
1511 #define DEBUG_PRINT4(a, b, c, d) if (debug) printf (a, b, c, d)
1512 #define DEBUG_PRINT5(a, b, c, d, e) if (debug) printf (a, b, c, d, e)
1515 /* ---------------------------------------------------------------------- */
1518 #ifndef M_PI
1519 #define M_PI 3.14159265358979323846
1520 #endif
1523 /* ---------------------------------------------------------------------- */
1526 /* A structure holding everything needed for a rotated string */
1528 typedef struct rotated_text_item_template {
1529 Pixmap bitmap;
1530 XImage *ximage;
1532 char *text;
1533 char *font_name;
1534 Font fid;
1535 float angle;
1536 int align;
1537 float magnify;
1539 int cols_in;
1540 int rows_in;
1541 int cols_out;
1542 int rows_out;
1544 int nl;
1545 int max_width;
1546 float *corners_x;
1547 float *corners_y;
1549 long int size;
1550 int cached;
1552 struct rotated_text_item_template *next;
1553 } RotatedTextItem;
1555 RotatedTextItem *first_text_item=NULL;
1558 /* ---------------------------------------------------------------------- */
1561 /* A structure holding current magnification and bounding box padding */
1563 static struct style_template {
1564 float magnify;
1565 int bbx_pad;
1566 } style={
1572 /* ---------------------------------------------------------------------- */
1575 static char *my_strdup();
1576 static char *my_strtok();
1578 static float XRotVersion();
1579 static void XRotSetMagnification();
1580 static void XRotSetBoundingBoxPad();
1581 static int XRotDrawString();
1582 static int XRotDrawImageString();
1583 static int XRotDrawAlignedString();
1584 static int XRotDrawAlignedImageString();
1585 static XPoint *XRotTextExtents();
1587 static XImage *MakeXImage();
1588 static int XRotPaintAlignedString();
1589 static int XRotDrawHorizontalString();
1590 static RotatedTextItem *XRotRetrieveFromCache();
1591 static RotatedTextItem *XRotCreateTextItem();
1592 static void XRotAddToLinkedList();
1593 static void XRotFreeTextItem();
1594 static XImage *XRotMagnifyImage();
1597 /* ---------------------------------------------------------------------- */
1600 /**************************************************************************/
1601 /* Routine to mimic `strdup()' (some machines don't have it) */
1602 /**************************************************************************/
1604 static char *my_strdup(str)
1605 char *str;
1607 char *s;
1609 if(str==NULL)
1610 return NULL;
1612 s=(char *)malloc((unsigned)(strlen(str)+1));
1613 if(s!=NULL)
1614 strcpy(s, str);
1616 return s;
1620 /* ---------------------------------------------------------------------- */
1623 /**************************************************************************/
1624 /* Routine to replace `strtok' : this one returns a zero length string if */
1625 /* it encounters two consecutive delimiters */
1626 /**************************************************************************/
1628 static char *my_strtok(str1, str2)
1629 char *str1, *str2;
1631 char *ret;
1632 int i, j, stop;
1633 static int start, len;
1634 static char *stext;
1636 if(str2==NULL)
1637 return NULL;
1639 /* initialise if str1 not NULL */
1640 if(str1!=NULL) {
1641 start=0;
1642 stext=str1;
1643 len=strlen(str1);
1646 /* run out of tokens ? */
1647 if(start>=len)
1648 return NULL;
1650 /* loop through characters */
1651 for(i=start; i<len; i++) {
1652 /* loop through delimiters */
1653 stop=0;
1654 for(j=0; j<strlen(str2); j++)
1655 if(stext[i]==str2[j])
1656 stop=1;
1658 if(stop)
1659 break;
1662 stext[i]='\0';
1664 ret=stext+start;
1666 start=i+1;
1668 return ret;
1672 /* ---------------------------------------------------------------------- */
1675 /**************************************************************************/
1676 /* Return version/copyright information */
1677 /**************************************************************************/
1678 static
1679 float XRotVersion(str, n)
1680 char *str;
1681 int n;
1683 if(str!=NULL)
1684 strncpy(str, XV_COPYRIGHT, n);
1685 return XV_VERSION;
1689 /* ---------------------------------------------------------------------- */
1692 /**************************************************************************/
1693 /* Set the font magnification factor for all subsequent operations */
1694 /**************************************************************************/
1695 static
1696 void XRotSetMagnification(m)
1697 float m;
1699 if(m>0.)
1700 style.magnify=m;
1704 /* ---------------------------------------------------------------------- */
1707 /**************************************************************************/
1708 /* Set the padding used when calculating bounding boxes */
1709 /**************************************************************************/
1710 static
1711 void XRotSetBoundingBoxPad(p)
1712 int p;
1714 if(p>=0)
1715 style.bbx_pad=p;
1719 /* ---------------------------------------------------------------------- */
1722 /**************************************************************************/
1723 /* Create an XImage structure and allocate memory for it */
1724 /**************************************************************************/
1726 static XImage *MakeXImage(dpy, w, h)
1727 Display *dpy;
1728 int w, h;
1730 XImage *I;
1731 char *data;
1733 /* reserve memory for image */
1734 data=(char *)calloc((unsigned)(((w-1)/8+1)*h), 1);
1735 if(data==NULL)
1736 return NULL;
1738 /* create the XImage */
1739 I=XCreateImage(dpy, DefaultVisual(dpy, DefaultScreen(dpy)), 1, XYBitmap,
1740 0, data, w, h, 8, 0);
1741 if(I==NULL)
1742 return NULL;
1744 I->byte_order=I->bitmap_bit_order=MSBFirst;
1745 return I;
1749 /* ---------------------------------------------------------------------- */
1752 /**************************************************************************/
1753 /* A front end to XRotPaintAlignedString: */
1754 /* -no alignment, no background */
1755 /**************************************************************************/
1756 static
1757 int XRotDrawString(dpy, font, angle, drawable, gc, x, y, str)
1758 Display *dpy;
1759 XFontStruct *font;
1760 float angle;
1761 Drawable drawable;
1762 GC gc;
1763 int x, y;
1764 char *str;
1766 return (XRotPaintAlignedString(dpy, font, angle, drawable, gc,
1767 x, y, str, NONE, 0));
1771 /* ---------------------------------------------------------------------- */
1774 /**************************************************************************/
1775 /* A front end to XRotPaintAlignedString: */
1776 /* -no alignment, paints background */
1777 /**************************************************************************/
1778 static
1779 int XRotDrawImageString(dpy, font, angle, drawable, gc, x, y, str)
1780 Display *dpy;
1781 XFontStruct *font;
1782 float angle;
1783 Drawable drawable;
1784 GC gc;
1785 int x, y;
1786 char *str;
1788 return(XRotPaintAlignedString(dpy, font, angle, drawable, gc,
1789 x, y, str, NONE, 1));
1793 /* ---------------------------------------------------------------------- */
1796 /**************************************************************************/
1797 /* A front end to XRotPaintAlignedString: */
1798 /* -does alignment, no background */
1799 /**************************************************************************/
1800 static
1801 int XRotDrawAlignedString(dpy, font, angle, drawable, gc, x, y, text, align)
1802 Display *dpy;
1803 XFontStruct *font;
1804 float angle;
1805 Drawable drawable;
1806 GC gc;
1807 int x, y;
1808 char *text;
1809 int align;
1811 return(XRotPaintAlignedString(dpy, font, angle, drawable, gc,
1812 x, y, text, align, 0));
1816 /* ---------------------------------------------------------------------- */
1819 /**************************************************************************/
1820 /* A front end to XRotPaintAlignedString: */
1821 /* -does alignment, paints background */
1822 /**************************************************************************/
1823 static
1824 int XRotDrawAlignedImageString(dpy, font, angle, drawable, gc, x, y, text,
1825 align)
1826 Display *dpy;
1827 XFontStruct *font;
1828 float angle;
1829 Drawable drawable;
1830 GC gc;
1831 int x, y;
1832 char *text;
1833 int align;
1835 return(XRotPaintAlignedString(dpy, font, angle, drawable, gc,
1836 x, y, text, align, 1));
1840 /* ---------------------------------------------------------------------- */
1843 /**************************************************************************/
1844 /* Aligns and paints a rotated string */
1845 /**************************************************************************/
1847 static int XRotPaintAlignedString(dpy, font, angle, drawable, gc, x, y, text,
1848 align, bg)
1849 Display *dpy;
1850 XFontStruct *font;
1851 float angle;
1852 Drawable drawable;
1853 GC gc;
1854 int x, y;
1855 char *text;
1856 int align;
1857 int bg;
1859 int i;
1860 GC my_gc;
1861 int xp, yp;
1862 float hot_x, hot_y;
1863 float hot_xp, hot_yp;
1864 float sin_angle, cos_angle;
1865 RotatedTextItem *item;
1866 Pixmap bitmap_to_paint;
1868 /* return early for NULL/empty strings */
1869 if(text==NULL)
1870 return 0;
1872 if(strlen(text)==0)
1873 return 0;
1875 /* manipulate angle to 0<=angle<360 degrees */
1876 while(angle<0)
1877 angle+=360;
1879 while(angle>=360)
1880 angle-=360;
1882 angle*=M_PI/180;
1884 /* horizontal text made easy */
1885 if(angle==0. && style.magnify==1.)
1886 return(XRotDrawHorizontalString(dpy, font, drawable, gc, x, y,
1887 text, align, bg));
1889 /* get a rotated bitmap */
1890 item=XRotRetrieveFromCache(dpy, font, angle, text, align);
1891 if(item==NULL)
1892 return NULL;
1894 /* this gc has similar properties to the user's gc */
1895 my_gc=XCreateGC(dpy, drawable, NULL, 0);
1896 XCopyGC(dpy, gc, GCForeground|GCBackground|GCFunction|GCPlaneMask
1897 |GCClipXOrigin|GCClipYOrigin|GCClipMask, my_gc);
1899 /* alignment : which point (hot_x, hot_y) relative to bitmap centre
1900 coincides with user's specified point? */
1902 /* y position */
1903 if(align==TLEFT || align==TCENTRE || align==TRIGHT)
1904 hot_y=(float)item->rows_in/2*style.magnify;
1905 else if(align==MLEFT || align==MCENTRE || align==MRIGHT)
1906 hot_y=0;
1907 else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
1908 hot_y = -(float)item->rows_in/2*style.magnify;
1909 else
1910 hot_y = -((float)item->rows_in/2-(float)font->descent)*style.magnify;
1912 /* x position */
1913 if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
1914 hot_x = -(float)item->max_width/2*style.magnify;
1915 else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
1916 hot_x=0;
1917 else
1918 hot_x=(float)item->max_width/2*style.magnify;
1920 /* pre-calculate sin and cos */
1921 sin_angle=sin(angle);
1922 cos_angle=cos(angle);
1924 /* rotate hot_x and hot_y around bitmap centre */
1925 hot_xp= hot_x*cos_angle - hot_y*sin_angle;
1926 hot_yp= hot_x*sin_angle + hot_y*cos_angle;
1928 /* text background will be drawn using XFillPolygon */
1929 if(bg) {
1930 GC depth_one_gc;
1931 XPoint *xpoints;
1932 Pixmap empty_stipple;
1934 /* reserve space for XPoints */
1935 xpoints=(XPoint *)malloc((unsigned)(4*item->nl*sizeof(XPoint)));
1936 if(!xpoints)
1937 return 1;
1939 /* rotate corner positions */
1940 for(i=0; i<4*item->nl; i++) {
1941 xpoints[i].x=(float)x + ( (item->corners_x[i]-hot_x)*cos_angle +
1942 (item->corners_y[i]+hot_y)*sin_angle);
1943 xpoints[i].y=(float)y + (-(item->corners_x[i]-hot_x)*sin_angle +
1944 (item->corners_y[i]+hot_y)*cos_angle);
1947 /* we want to swap foreground and background colors here;
1948 XGetGCValues() is only available in R4+ */
1950 empty_stipple=XCreatePixmap(dpy, drawable, 1, 1, 1);
1952 depth_one_gc=XCreateGC(dpy, empty_stipple, NULL, 0);
1953 XSetForeground(dpy, depth_one_gc, 0);
1954 XFillRectangle(dpy, empty_stipple, depth_one_gc, 0, 0, 2, 2);
1956 XSetStipple(dpy, my_gc, empty_stipple);
1957 XSetFillStyle(dpy, my_gc, FillOpaqueStippled);
1959 XFillPolygon(dpy, drawable, my_gc, xpoints, 4*item->nl, Nonconvex,
1960 CoordModeOrigin);
1962 /* free our resources */
1963 free((char *)xpoints);
1964 XFreeGC(dpy, depth_one_gc);
1965 XFreePixmap(dpy, empty_stipple);
1968 /* where should top left corner of bitmap go ? */
1969 xp=(float)x-((float)item->cols_out/2 +hot_xp);
1970 yp=(float)y-((float)item->rows_out/2 -hot_yp);
1972 /* by default we draw the rotated bitmap, solid */
1973 bitmap_to_paint=item->bitmap;
1975 /* handle user stippling */
1976 #ifndef X11R3
1978 GC depth_one_gc;
1979 XGCValues values;
1980 Pixmap new_bitmap, inverse;
1982 /* try and get some GC properties */
1983 if(XGetGCValues(dpy, gc,
1984 GCStipple|GCFillStyle|GCForeground|GCBackground|
1985 GCTileStipXOrigin|GCTileStipYOrigin,
1986 &values)) {
1988 /* only do this if stippling requested */
1989 if((values.fill_style==FillStippled ||
1990 values.fill_style==FillOpaqueStippled) && !bg) {
1992 /* opaque stipple: draw rotated text in background colour */
1993 if(values.fill_style==FillOpaqueStippled) {
1994 XSetForeground(dpy, my_gc, values.background);
1995 XSetFillStyle(dpy, my_gc, FillStippled);
1996 XSetStipple(dpy, my_gc, item->bitmap);
1997 XSetTSOrigin(dpy, my_gc, xp, yp);
1998 XFillRectangle(dpy, drawable, my_gc, xp, yp,
1999 item->cols_out, item->rows_out);
2000 XSetForeground(dpy, my_gc, values.foreground);
2003 /* this will merge the rotated text and the user's stipple */
2004 new_bitmap=XCreatePixmap(dpy, drawable,
2005 item->cols_out, item->rows_out, 1);
2007 /* create a GC */
2008 depth_one_gc=XCreateGC(dpy, new_bitmap, NULL, 0);
2009 XSetForeground(dpy, depth_one_gc, 1);
2010 XSetBackground(dpy, depth_one_gc, 0);
2012 /* set the relative stipple origin */
2013 XSetTSOrigin(dpy, depth_one_gc,
2014 values.ts_x_origin-xp, values.ts_y_origin-yp);
2016 /* fill the whole bitmap with the user's stipple */
2017 XSetStipple(dpy, depth_one_gc, values.stipple);
2018 XSetFillStyle(dpy, depth_one_gc, FillOpaqueStippled);
2019 XFillRectangle(dpy, new_bitmap, depth_one_gc,
2020 0, 0, item->cols_out, item->rows_out);
2022 /* set stipple origin back to normal */
2023 XSetTSOrigin(dpy, depth_one_gc, 0, 0);
2025 /* this will contain an inverse copy of the rotated text */
2026 inverse=XCreatePixmap(dpy, drawable,
2027 item->cols_out, item->rows_out, 1);
2029 /* invert text */
2030 XSetFillStyle(dpy, depth_one_gc, FillSolid);
2031 XSetFunction(dpy, depth_one_gc, GXcopyInverted);
2032 XCopyArea(dpy, item->bitmap, inverse, depth_one_gc,
2033 0, 0, item->cols_out, item->rows_out, 0, 0);
2035 /* now delete user's stipple everywhere EXCEPT on text */
2036 XSetForeground(dpy, depth_one_gc, 0);
2037 XSetBackground(dpy, depth_one_gc, 1);
2038 XSetStipple(dpy, depth_one_gc, inverse);
2039 XSetFillStyle(dpy, depth_one_gc, FillStippled);
2040 XSetFunction(dpy, depth_one_gc, GXcopy);
2041 XFillRectangle(dpy, new_bitmap, depth_one_gc,
2042 0, 0, item->cols_out, item->rows_out);
2044 /* free resources */
2045 XFreePixmap(dpy, inverse);
2046 XFreeGC(dpy, depth_one_gc);
2048 /* this is the new bitmap */
2049 bitmap_to_paint=new_bitmap;
2053 #endif /*X11R3*/
2055 /* paint text using stipple technique */
2056 XSetFillStyle(dpy, my_gc, FillStippled);
2057 XSetStipple(dpy, my_gc, bitmap_to_paint);
2058 XSetTSOrigin(dpy, my_gc, xp, yp);
2059 XFillRectangle(dpy, drawable, my_gc, xp, yp,
2060 item->cols_out, item->rows_out);
2062 /* free our resources */
2063 XFreeGC(dpy, my_gc);
2065 /* stippled bitmap no longer needed */
2066 if(bitmap_to_paint!=item->bitmap)
2067 XFreePixmap(dpy, bitmap_to_paint);
2069 #ifdef CACHE_XIMAGES
2070 XFreePixmap(dpy, item->bitmap);
2071 #endif /*CACHE_XIMAGES*/
2073 /* if item isn't cached, destroy it completely */
2074 if(!item->cached)
2075 XRotFreeTextItem(dpy,item);
2077 /* we got to the end OK! */
2078 return 0;
2082 /* ---------------------------------------------------------------------- */
2085 /**************************************************************************/
2086 /* Draw a horizontal string in a quick fashion */
2087 /**************************************************************************/
2089 static int XRotDrawHorizontalString(dpy, font, drawable, gc, x, y, text,
2090 align, bg)
2091 Display *dpy;
2092 XFontStruct *font;
2093 Drawable drawable;
2094 GC gc;
2095 int x, y;
2096 char *text;
2097 int align;
2098 int bg;
2100 GC my_gc;
2101 int nl=1, i;
2102 int height;
2103 int xp, yp;
2104 char *str1, *str2, *str3;
2105 char *str2_a="\0", *str2_b="\n\0";
2106 int dir, asc, desc;
2107 XCharStruct overall;
2109 DEBUG_PRINT1("**\nHorizontal text.\n");
2111 /* this gc has similar properties to the user's gc (including stipple) */
2112 my_gc=XCreateGC(dpy, drawable, NULL, 0);
2113 XCopyGC(dpy, gc,
2114 GCForeground|GCBackground|GCFunction|GCStipple|GCFillStyle|
2115 GCTileStipXOrigin|GCTileStipYOrigin|GCPlaneMask|
2116 GCClipXOrigin|GCClipYOrigin|GCClipMask, my_gc);
2117 XSetFont(dpy, my_gc, font->fid);
2119 /* count number of sections in string */
2120 if(align!=NONE)
2121 for(i=0; i<strlen(text)-1; i++)
2122 if(text[i]=='\n')
2123 nl++;
2125 /* ignore newline characters if not doing alignment */
2126 if(align==NONE)
2127 str2=str2_a;
2128 else
2129 str2=str2_b;
2131 /* overall font height */
2132 height=font->ascent+font->descent;
2134 /* y position */
2135 if(align==TLEFT || align==TCENTRE || align==TRIGHT)
2136 yp=y+font->ascent;
2137 else if(align==MLEFT || align==MCENTRE || align==MRIGHT)
2138 yp=y-nl*height/2+font->ascent;
2139 else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
2140 yp=y-nl*height+font->ascent;
2141 else
2142 yp=y;
2144 str1=my_strdup(text);
2145 if(str1==NULL)
2146 return 1;
2148 str3=my_strtok(str1, str2);
2150 /* loop through each section in the string */
2151 do {
2152 XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
2153 &overall);
2155 /* where to draw section in x ? */
2156 if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
2157 xp=x;
2158 else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
2159 xp=x-overall.rbearing/2;
2160 else
2161 xp=x-overall.rbearing;
2163 /* draw string onto bitmap */
2164 if(!bg)
2165 XDrawString(dpy, drawable, my_gc, xp, yp, str3, strlen(str3));
2166 else
2167 XDrawImageString(dpy, drawable, my_gc, xp, yp, str3, strlen(str3));
2169 /* move to next line */
2170 yp+=height;
2172 str3=my_strtok((char *)NULL, str2);
2174 while(str3!=NULL);
2176 free(str1);
2177 XFreeGC(dpy, my_gc);
2179 return 0;
2183 /* ---------------------------------------------------------------------- */
2186 /**************************************************************************/
2187 /* Query cache for a match with this font/text/angle/alignment */
2188 /* request, otherwise arrange for its creation */
2189 /**************************************************************************/
2191 static RotatedTextItem *XRotRetrieveFromCache(dpy, font, angle, text, align)
2192 Display *dpy;
2193 XFontStruct *font;
2194 float angle;
2195 char *text;
2196 int align;
2198 Font fid;
2199 char *font_name=NULL;
2200 unsigned long name_value;
2201 RotatedTextItem *item=NULL;
2202 RotatedTextItem *i1=first_text_item;
2204 /* get font name, if it exists */
2205 if(XGetFontProperty(font, XA_FONT, &name_value)) {
2206 DEBUG_PRINT1("got font name OK\n");
2207 font_name=XGetAtomName(dpy, name_value);
2208 fid=0;
2210 #ifdef CACHE_FID
2211 /* otherwise rely (unreliably?) on font ID */
2212 else {
2213 DEBUG_PRINT1("can't get fontname, caching FID\n");
2214 font_name=NULL;
2215 fid=font->fid;
2217 #else
2218 /* not allowed to cache font ID's */
2219 else {
2220 DEBUG_PRINT1("can't get fontname, can't cache\n");
2221 font_name=NULL;
2222 fid=0;
2224 #endif /*CACHE_FID*/
2226 /* look for a match in cache */
2228 /* matching formula:
2229 identical text;
2230 identical fontname (if defined, font ID's if not);
2231 angles close enough (<0.00001 here, could be smaller);
2232 HORIZONTAL alignment matches, OR it's a one line string;
2233 magnifications the same */
2235 while(i1 && !item) {
2236 /* match everything EXCEPT fontname/ID */
2237 if(strcmp(text, i1->text)==0 &&
2238 fabs(angle-i1->angle)<0.00001 &&
2239 style.magnify==i1->magnify &&
2240 (i1->nl==1 ||
2241 ((align==0)?9:(align-1))%3==
2242 ((i1->align==0)?9:(i1->align-1))%3)) {
2244 /* now match fontname/ID */
2245 if(font_name!=NULL && i1->font_name!=NULL) {
2246 if(strcmp(font_name, i1->font_name)==0) {
2247 item=i1;
2248 DEBUG_PRINT1("Matched against font names\n");
2250 else
2251 i1=i1->next;
2253 #ifdef CACHE_FID
2254 else if(font_name==NULL && i1->font_name==NULL) {
2255 if(fid==i1->fid) {
2256 item=i1;
2257 DEBUG_PRINT1("Matched against FID's\n");
2259 else
2260 i1=i1->next;
2262 #endif /*CACHE_FID*/
2263 else
2264 i1=i1->next;
2266 else
2267 i1=i1->next;
2270 if(item)
2271 DEBUG_PRINT1("**\nFound target in cache.\n");
2272 if(!item)
2273 DEBUG_PRINT1("**\nNo match in cache.\n");
2275 /* no match */
2276 if(!item) {
2277 /* create new item */
2278 item=XRotCreateTextItem(dpy, font, angle, text, align);
2279 if(!item)
2280 return NULL;
2282 /* record what it shows */
2283 item->text=my_strdup(text);
2285 /* fontname or ID */
2286 if(font_name!=NULL) {
2287 item->font_name=my_strdup(font_name);
2288 item->fid=0;
2290 else {
2291 item->font_name=NULL;
2292 item->fid=fid;
2295 item->angle=angle;
2296 item->align=align;
2297 item->magnify=style.magnify;
2299 /* cache it */
2300 XRotAddToLinkedList(dpy, item);
2303 if(font_name)
2304 XFree(font_name);
2306 /* if XImage is cached, need to recreate the bitmap */
2308 #ifdef CACHE_XIMAGES
2310 GC depth_one_gc;
2312 /* create bitmap to hold rotated text */
2313 item->bitmap=XCreatePixmap(dpy, DefaultRootWindow(dpy),
2314 item->cols_out, item->rows_out, 1);
2316 /* depth one gc */
2317 depth_one_gc=XCreateGC(dpy, item->bitmap, NULL, 0);
2318 XSetBackground(dpy, depth_one_gc, 0);
2319 XSetForeground(dpy, depth_one_gc, 1);
2321 /* make the text bitmap from XImage */
2322 XPutImage(dpy, item->bitmap, depth_one_gc, item->ximage, 0, 0, 0, 0,
2323 item->cols_out, item->rows_out);
2325 XFreeGC(dpy, depth_one_gc);
2327 #endif /*CACHE_XIMAGES*/
2329 return item;
2333 /* ---------------------------------------------------------------------- */
2336 /**************************************************************************/
2337 /* Create a rotated text item */
2338 /**************************************************************************/
2340 static RotatedTextItem *XRotCreateTextItem(dpy, font, angle, text, align)
2341 Display *dpy;
2342 XFontStruct *font;
2343 float angle;
2344 char *text;
2345 int align;
2347 RotatedTextItem *item=NULL;
2348 Pixmap canvas;
2349 GC font_gc;
2350 XImage *I_in;
2351 register int i, j;
2352 char *str1, *str2, *str3;
2353 char *str2_a="\0", *str2_b="\n\0";
2354 int height;
2355 int byte_w_in, byte_w_out;
2356 int xp, yp;
2357 float sin_angle, cos_angle;
2358 int it, jt;
2359 float di, dj;
2360 int ic=0;
2361 float xl, xr, xinc;
2362 int byte_out;
2363 int dir, asc, desc;
2364 XCharStruct overall;
2365 int old_cols_in=0, old_rows_in=0;
2367 /* allocate memory */
2368 item=(RotatedTextItem *)malloc((unsigned)sizeof(RotatedTextItem));
2369 if(!item)
2370 return NULL;
2372 /* count number of sections in string */
2373 item->nl=1;
2374 if(align!=NONE)
2375 for(i=0; i<strlen(text)-1; i++)
2376 if(text[i]=='\n')
2377 item->nl++;
2379 /* ignore newline characters if not doing alignment */
2380 if(align==NONE)
2381 str2=str2_a;
2382 else
2383 str2=str2_b;
2385 /* find width of longest section */
2386 str1=my_strdup(text);
2387 if(str1==NULL)
2388 return NULL;
2390 str3=my_strtok(str1, str2);
2392 XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
2393 &overall);
2395 item->max_width=overall.rbearing;
2397 /* loop through each section */
2398 do {
2399 str3=my_strtok((char *)NULL, str2);
2401 if(str3!=NULL) {
2402 XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
2403 &overall);
2405 if(overall.rbearing>item->max_width)
2406 item->max_width=overall.rbearing;
2409 while(str3!=NULL);
2411 free(str1);
2413 /* overall font height */
2414 height=font->ascent+font->descent;
2416 /* dimensions horizontal text will have */
2417 item->cols_in=item->max_width;
2418 item->rows_in=item->nl*height;
2420 /* bitmap for drawing on */
2421 canvas=XCreatePixmap(dpy, DefaultRootWindow(dpy),
2422 item->cols_in, item->rows_in, 1);
2424 /* create a GC for the bitmap */
2425 font_gc=XCreateGC(dpy, canvas, NULL, 0);
2426 XSetBackground(dpy, font_gc, 0);
2427 XSetFont(dpy, font_gc, font->fid);
2429 /* make sure the bitmap is blank */
2430 XSetForeground(dpy, font_gc, 0);
2431 XFillRectangle(dpy, canvas, font_gc, 0, 0,
2432 item->cols_in+1, item->rows_in+1);
2433 XSetForeground(dpy, font_gc, 1);
2435 /* pre-calculate sin and cos */
2436 sin_angle=sin(angle);
2437 cos_angle=cos(angle);
2439 /* text background will be drawn using XFillPolygon */
2440 item->corners_x=
2441 (float *)malloc((unsigned)(4*item->nl*sizeof(float)));
2442 if(!item->corners_x)
2443 return NULL;
2445 item->corners_y=
2446 (float *)malloc((unsigned)(4*item->nl*sizeof(float)));
2447 if(!item->corners_y)
2448 return NULL;
2450 /* draw text horizontally */
2452 /* start at top of bitmap */
2453 yp=font->ascent;
2455 str1=my_strdup(text);
2456 if(str1==NULL)
2457 return NULL;
2459 str3=my_strtok(str1, str2);
2461 /* loop through each section in the string */
2462 do {
2463 XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
2464 &overall);
2466 /* where to draw section in x ? */
2467 if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
2468 xp=0;
2469 else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
2470 xp=(item->max_width-overall.rbearing)/2;
2471 else
2472 xp=item->max_width-overall.rbearing;
2474 /* draw string onto bitmap */
2475 XDrawString(dpy, canvas, font_gc, xp, yp, str3, strlen(str3));
2477 /* keep a note of corner positions of this string */
2478 item->corners_x[ic]=((float)xp-(float)item->cols_in/2)*style.magnify;
2479 item->corners_y[ic]=((float)(yp-font->ascent)-(float)item->rows_in/2)
2480 *style.magnify;
2481 item->corners_x[ic+1]=item->corners_x[ic];
2482 item->corners_y[ic+1]=item->corners_y[ic]+(float)height*style.magnify;
2483 item->corners_x[item->nl*4-1-ic]=item->corners_x[ic]+
2484 (float)overall.rbearing*style.magnify;
2485 item->corners_y[item->nl*4-1-ic]=item->corners_y[ic];
2486 item->corners_x[item->nl*4-2-ic]=
2487 item->corners_x[item->nl*4-1-ic];
2488 item->corners_y[item->nl*4-2-ic]=item->corners_y[ic+1];
2490 ic+=2;
2492 /* move to next line */
2493 yp+=height;
2495 str3=my_strtok((char *)NULL, str2);
2497 while(str3!=NULL);
2499 free(str1);
2501 /* create image to hold horizontal text */
2502 I_in=MakeXImage(dpy, item->cols_in, item->rows_in);
2503 if(I_in==NULL)
2504 return NULL;
2506 /* extract horizontal text */
2507 XGetSubImage(dpy, canvas, 0, 0, item->cols_in, item->rows_in,
2508 1, XYPixmap, I_in, 0, 0);
2509 I_in->format=XYBitmap;
2511 /* magnify horizontal text */
2512 if(style.magnify!=1.) {
2513 I_in=XRotMagnifyImage(dpy, I_in);
2515 old_cols_in=item->cols_in;
2516 old_rows_in=item->rows_in;
2517 item->cols_in=(float)item->cols_in*style.magnify;
2518 item->rows_in=(float)item->rows_in*style.magnify;
2521 /* how big will rotated text be ? */
2522 item->cols_out=fabs((float)item->rows_in*sin_angle) +
2523 fabs((float)item->cols_in*cos_angle) +0.99999 +2;
2525 item->rows_out=fabs((float)item->rows_in*cos_angle) +
2526 fabs((float)item->cols_in*sin_angle) +0.99999 +2;
2528 if(item->cols_out%2==0)
2529 item->cols_out++;
2531 if(item->rows_out%2==0)
2532 item->rows_out++;
2534 /* create image to hold rotated text */
2535 item->ximage=MakeXImage(dpy, item->cols_out, item->rows_out);
2536 if(item->ximage==NULL)
2537 return NULL;
2539 byte_w_in=(item->cols_in-1)/8+1;
2540 byte_w_out=(item->cols_out-1)/8+1;
2542 /* we try to make this bit as fast as possible - which is why it looks
2543 a bit over-the-top */
2545 /* vertical distance from centre */
2546 dj=0.5-(float)item->rows_out/2;
2548 /* where abouts does text actually lie in rotated image? */
2549 if(angle==0 || angle==M_PI/2 ||
2550 angle==M_PI || angle==3*M_PI/2) {
2551 xl=0;
2552 xr=(float)item->cols_out;
2553 xinc=0;
2555 else if(angle<M_PI) {
2556 xl=(float)item->cols_out/2+
2557 (dj-(float)item->rows_in/(2*cos_angle))/
2558 tan(angle)-2;
2559 xr=(float)item->cols_out/2+
2560 (dj+(float)item->rows_in/(2*cos_angle))/
2561 tan(angle)+2;
2562 xinc=1./tan(angle);
2564 else {
2565 xl=(float)item->cols_out/2+
2566 (dj+(float)item->rows_in/(2*cos_angle))/
2567 tan(angle)-2;
2568 xr=(float)item->cols_out/2+
2569 (dj-(float)item->rows_in/(2*cos_angle))/
2570 tan(angle)+2;
2572 xinc=1./tan(angle);
2575 /* loop through all relevent bits in rotated image */
2576 for(j=0; j<item->rows_out; j++) {
2578 /* no point re-calculating these every pass */
2579 di=(float)((xl<0)?0:(int)xl)+0.5-(float)item->cols_out/2;
2580 byte_out=(item->rows_out-j-1)*byte_w_out;
2582 /* loop through meaningful columns */
2583 for(i=((xl<0)?0:(int)xl);
2584 i<((xr>=item->cols_out)?item->cols_out:(int)xr); i++) {
2586 /* rotate coordinates */
2587 it=(float)item->cols_in/2 + ( di*cos_angle + dj*sin_angle);
2588 jt=(float)item->rows_in/2 - (-di*sin_angle + dj*cos_angle);
2590 /* set pixel if required */
2591 if(it>=0 && it<item->cols_in && jt>=0 && jt<item->rows_in)
2592 if((I_in->data[jt*byte_w_in+it/8] & 128>>(it%8))>0)
2593 item->ximage->data[byte_out+i/8]|=128>>i%8;
2595 di+=1;
2597 dj+=1;
2598 xl+=xinc;
2599 xr+=xinc;
2601 XDestroyImage(I_in);
2603 if(style.magnify!=1.) {
2604 item->cols_in=old_cols_in;
2605 item->rows_in=old_rows_in;
2609 #ifdef CACHE_BITMAPS
2611 /* create a bitmap to hold rotated text */
2612 item->bitmap=XCreatePixmap(dpy, DefaultRootWindow(dpy),
2613 item->cols_out, item->rows_out, 1);
2615 /* make the text bitmap from XImage */
2616 XPutImage(dpy, item->bitmap, font_gc, item->ximage, 0, 0, 0, 0,
2617 item->cols_out, item->rows_out);
2619 XDestroyImage(item->ximage);
2621 #endif /*CACHE_BITMAPS*/
2623 XFreeGC(dpy, font_gc);
2624 XFreePixmap(dpy, canvas);
2626 return item;
2630 /* ---------------------------------------------------------------------- */
2633 /**************************************************************************/
2634 /* Adds a text item to the end of the cache, removing as many items */
2635 /* from the front as required to keep cache size below limit */
2636 /**************************************************************************/
2638 static void XRotAddToLinkedList(dpy, item)
2639 Display *dpy;
2640 RotatedTextItem *item;
2643 static long int current_size=0;
2644 static RotatedTextItem *last=NULL;
2645 RotatedTextItem *i1=first_text_item, *i2=NULL;
2647 #ifdef CACHE_BITMAPS
2649 /* I don't know how much memory a pixmap takes in the server -
2650 probably this + a bit more we can't account for */
2652 item->size=((item->cols_out-1)/8+1)*item->rows_out;
2654 #else
2656 /* this is pretty much the size of a RotatedTextItem */
2658 item->size=((item->cols_out-1)/8+1)*item->rows_out +
2659 sizeof(XImage) + strlen(item->text) +
2660 item->nl*8*sizeof(float) + sizeof(RotatedTextItem);
2662 if(item->font_name!=NULL)
2663 item->size+=strlen(item->font_name);
2664 else
2665 item->size+=sizeof(Font);
2667 #endif /*CACHE_BITMAPS */
2669 #ifdef DEBUG
2670 /* count number of items in cache, for debugging */
2672 int i=0;
2674 while(i1) {
2675 i++;
2676 i1=i1->next;
2678 DEBUG_PRINT2("Cache has %d items.\n", i);
2679 i1=first_text_item;
2681 #endif
2683 DEBUG_PRINT4("current cache size=%ld, new item=%ld, limit=%ld\n",
2684 current_size, item->size, CACHE_SIZE_LIMIT*1024);
2686 /* if this item is bigger than whole cache, forget it */
2687 if(item->size>CACHE_SIZE_LIMIT*1024) {
2688 DEBUG_PRINT1("Too big to cache\n\n");
2689 item->cached=0;
2690 return;
2693 /* remove elements from cache as needed */
2694 while(i1 && current_size+item->size>CACHE_SIZE_LIMIT*1024) {
2696 DEBUG_PRINT2("Removed %d bytes\n", i1->size);
2698 if(i1->font_name!=NULL)
2699 DEBUG_PRINT5(" (`%s'\n %s\n angle=%f align=%d)\n",
2700 i1->text, i1->font_name, i1->angle, i1->align);
2702 #ifdef CACHE_FID
2703 if(i1->font_name==NULL)
2704 DEBUG_PRINT5(" (`%s'\n FID=%ld\n angle=%f align=%d)\n",
2705 i1->text, i1->fid, i1->angle, i1->align);
2706 #endif /*CACHE_FID*/
2708 current_size-=i1->size;
2710 i2=i1->next;
2712 /* free resources used by the unlucky item */
2713 XRotFreeTextItem(dpy, i1);
2715 /* remove it from linked list */
2716 first_text_item=i2;
2717 i1=i2;
2720 /* add new item to end of linked list */
2721 if(first_text_item==NULL) {
2722 item->next=NULL;
2723 first_text_item=item;
2724 last=item;
2726 else {
2727 item->next=NULL;
2728 last->next=item;
2729 last=item;
2732 /* new cache size */
2733 current_size+=item->size;
2735 item->cached=1;
2737 DEBUG_PRINT1("Added item to cache.\n");
2741 /* ---------------------------------------------------------------------- */
2744 /**************************************************************************/
2745 /* Free the resources used by a text item */
2746 /**************************************************************************/
2748 static void XRotFreeTextItem(dpy, item)
2749 Display *dpy;
2750 RotatedTextItem *item;
2752 free(item->text);
2754 if(item->font_name!=NULL)
2755 free(item->font_name);
2757 free((char *)item->corners_x);
2758 free((char *)item->corners_y);
2760 #ifdef CACHE_BITMAPS
2761 XFreePixmap(dpy, item->bitmap);
2762 #else
2763 XDestroyImage(item->ximage);
2764 #endif /* CACHE_BITMAPS */
2766 free((char *)item);
2770 /* ---------------------------------------------------------------------- */
2773 /**************************************************************************/
2774 /* Magnify an XImage using bilinear interpolation */
2775 /**************************************************************************/
2777 static XImage *XRotMagnifyImage(dpy, ximage)
2778 Display *dpy;
2779 XImage *ximage;
2781 int i, j;
2782 float x, y;
2783 float u,t;
2784 XImage *I_out;
2785 int cols_in, rows_in;
2786 int cols_out, rows_out;
2787 register int i2, j2;
2788 float z1, z2, z3, z4;
2789 int byte_width_in, byte_width_out;
2790 float mag_inv;
2792 /* size of input image */
2793 cols_in=ximage->width;
2794 rows_in=ximage->height;
2796 /* size of final image */
2797 cols_out=(float)cols_in*style.magnify;
2798 rows_out=(float)rows_in*style.magnify;
2800 /* this will hold final image */
2801 I_out=MakeXImage(dpy, cols_out, rows_out);
2802 if(I_out==NULL)
2803 return NULL;
2805 /* width in bytes of input, output images */
2806 byte_width_in=(cols_in-1)/8+1;
2807 byte_width_out=(cols_out-1)/8+1;
2809 /* for speed */
2810 mag_inv=1./style.magnify;
2812 y=0.;
2814 /* loop over magnified image */
2815 for(j2=0; j2<rows_out; j2++) {
2816 x=0;
2817 j=y;
2819 for(i2=0; i2<cols_out; i2++) {
2820 i=x;
2822 /* bilinear interpolation - where are we on bitmap ? */
2823 /* right edge */
2824 if(i==cols_in-1 && j!=rows_in-1) {
2825 t=0;
2826 u=y-(float)j;
2828 z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
2829 z2=z1;
2830 z3=(ximage->data[(j+1)*byte_width_in+i/8] & 128>>(i%8))>0;
2831 z4=z3;
2833 /* top edge */
2834 else if(i!=cols_in-1 && j==rows_in-1) {
2835 t=x-(float)i;
2836 u=0;
2838 z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
2839 z2=(ximage->data[j*byte_width_in+(i+1)/8] & 128>>((i+1)%8))>0;
2840 z3=z2;
2841 z4=z1;
2843 /* top right corner */
2844 else if(i==cols_in-1 && j==rows_in-1) {
2845 u=0;
2846 t=0;
2848 z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
2849 z2=z1;
2850 z3=z1;
2851 z4=z1;
2853 /* somewhere `safe' */
2854 else {
2855 t=x-(float)i;
2856 u=y-(float)j;
2858 z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
2859 z2=(ximage->data[j*byte_width_in+(i+1)/8] & 128>>((i+1)%8))>0;
2860 z3=(ximage->data[(j+1)*byte_width_in+(i+1)/8] &
2861 128>>((i+1)%8))>0;
2862 z4=(ximage->data[(j+1)*byte_width_in+i/8] & 128>>(i%8))>0;
2865 /* if interpolated value is greater than 0.5, set bit */
2866 if(((1-t)*(1-u)*z1 + t*(1-u)*z2 + t*u*z3 + (1-t)*u*z4)>0.5)
2867 I_out->data[j2*byte_width_out+i2/8]|=128>>i2%8;
2869 x+=mag_inv;
2871 y+=mag_inv;
2874 /* destroy original */
2875 XDestroyImage(ximage);
2877 /* return big image */
2878 return I_out;
2883 /* ---------------------------------------------------------------------- */
2886 /**************************************************************************/
2887 /* Calculate the bounding box some text will have when painted */
2888 /**************************************************************************/
2889 static
2890 XPoint *XRotTextExtents(dpy, font, angle, x, y, text, align)
2891 Display *dpy;
2892 XFontStruct *font;
2893 float angle;
2894 int x, y;
2895 char *text;
2896 int align;
2898 register int i;
2899 char *str1, *str2, *str3;
2900 char *str2_a="\0", *str2_b="\n\0";
2901 int height;
2902 float sin_angle, cos_angle;
2903 int nl, max_width;
2904 int cols_in, rows_in;
2905 float hot_x, hot_y;
2906 XPoint *xp_in, *xp_out;
2907 int dir, asc, desc;
2908 XCharStruct overall;
2910 /* manipulate angle to 0<=angle<360 degrees */
2911 while(angle<0)
2912 angle+=360;
2914 while(angle>360)
2915 angle-=360;
2917 angle*=M_PI/180;
2919 /* count number of sections in string */
2920 nl=1;
2921 if(align!=NONE)
2922 for(i=0; i<strlen(text)-1; i++)
2923 if(text[i]=='\n')
2924 nl++;
2926 /* ignore newline characters if not doing alignment */
2927 if(align==NONE)
2928 str2=str2_a;
2929 else
2930 str2=str2_b;
2932 /* find width of longest section */
2933 str1=my_strdup(text);
2934 if(str1==NULL)
2935 return NULL;
2937 str3=my_strtok(str1, str2);
2939 XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
2940 &overall);
2942 max_width=overall.rbearing;
2944 /* loop through each section */
2945 do {
2946 str3=my_strtok((char *)NULL, str2);
2948 if(str3!=NULL) {
2949 XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
2950 &overall);
2952 if(overall.rbearing>max_width)
2953 max_width=overall.rbearing;
2956 while(str3!=NULL);
2958 free(str1);
2960 /* overall font height */
2961 height=font->ascent+font->descent;
2963 /* dimensions horizontal text will have */
2964 cols_in=max_width;
2965 rows_in=nl*height;
2967 /* pre-calculate sin and cos */
2968 sin_angle=sin(angle);
2969 cos_angle=cos(angle);
2971 /* y position */
2972 if(align==TLEFT || align==TCENTRE || align==TRIGHT)
2973 hot_y=(float)rows_in/2*style.magnify;
2974 else if(align==MLEFT || align==MCENTRE || align==MRIGHT)
2975 hot_y=0;
2976 else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
2977 hot_y = -(float)rows_in/2*style.magnify;
2978 else
2979 hot_y = -((float)rows_in/2-(float)font->descent)*style.magnify;
2981 /* x position */
2982 if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
2983 hot_x = -(float)max_width/2*style.magnify;
2984 else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
2985 hot_x=0;
2986 else
2987 hot_x=(float)max_width/2*style.magnify;
2989 /* reserve space for XPoints */
2990 xp_in=(XPoint *)malloc((unsigned)(5*sizeof(XPoint)));
2991 if(!xp_in)
2992 return NULL;
2994 xp_out=(XPoint *)malloc((unsigned)(5*sizeof(XPoint)));
2995 if(!xp_out)
2996 return NULL;
2998 /* bounding box when horizontal, relative to bitmap centre */
2999 xp_in[0].x = -(float)cols_in*style.magnify/2-style.bbx_pad;
3000 xp_in[0].y= (float)rows_in*style.magnify/2+style.bbx_pad;
3001 xp_in[1].x= (float)cols_in*style.magnify/2+style.bbx_pad;
3002 xp_in[1].y= (float)rows_in*style.magnify/2+style.bbx_pad;
3003 xp_in[2].x= (float)cols_in*style.magnify/2+style.bbx_pad;
3004 xp_in[2].y = -(float)rows_in*style.magnify/2-style.bbx_pad;
3005 xp_in[3].x = -(float)cols_in*style.magnify/2-style.bbx_pad;
3006 xp_in[3].y = -(float)rows_in*style.magnify/2-style.bbx_pad;
3007 xp_in[4].x=xp_in[0].x;
3008 xp_in[4].y=xp_in[0].y;
3010 /* rotate and translate bounding box */
3011 for(i=0; i<5; i++) {
3012 xp_out[i].x=(float)x + ( ((float)xp_in[i].x-hot_x)*cos_angle +
3013 ((float)xp_in[i].y+hot_y)*sin_angle);
3014 xp_out[i].y=(float)y + (-((float)xp_in[i].x-hot_x)*sin_angle +
3015 ((float)xp_in[i].y+hot_y)*cos_angle);
3018 free((char *)xp_in);
3020 return xp_out;
3025 /* ***********************************************************************
3026 * Conversion routines for the X resource manager
3027 * ***********************************************************************
3030 #if defined(__STDC__)
3031 static
3032 Boolean strtocard( Display *dsp,
3033 XrmValue *args,
3034 Cardinal *num_args,
3035 XrmValue *from,
3036 XrmValue *to,
3037 XtPointer *unused
3039 #else
3040 static
3041 Boolean strtocard( dsp, args, num_args, from, to, unused )
3042 Display *dsp;
3043 XrmValue *args;
3044 Cardinal *num_args;
3045 XrmValue *from;
3046 XrmValue *to;
3047 XtPointer *unused;
3048 #endif
3050 static Cardinal temp;
3052 if ( to->addr == NULL ) {
3053 to->addr = (XtPointer) &temp;
3054 to->size = sizeof(Cardinal);
3057 *((Cardinal *) to->addr) = atoi( from->addr );
3058 return True;
3062 #define done_bert(type, value) \
3063 do {\
3064 if (to->addr != NULL) {\
3065 if (to->size < sizeof(type)) {\
3066 to->size = sizeof(type);\
3067 return False;\
3069 *(type*)(to->addr) = (value);\
3070 } else {\
3071 static type static_val;\
3072 static_val = (value);\
3073 to->addr = (XtPointer)&static_val;\
3075 to->size = sizeof(type);\
3076 return True;\
3077 } while (0)
3078 static
3079 Boolean cvtStringToStringArray(display, args, num_args, from, to,
3080 converter_data)
3081 Display *display;
3082 XrmValuePtr args;
3083 Cardinal *num_args;
3084 XrmValuePtr from;
3085 XrmValuePtr to;
3086 XtPointer *converter_data;
3088 String t, s;
3089 StringArray a = NULL;
3090 Cardinal i;
3091 char delim;
3093 if (*num_args != 0)
3094 XtAppErrorMsg(XtDisplayToApplicationContext(display),
3095 "cvtStringToStringArray", "wrongParameters",
3096 "XtToolkitError",
3097 "String to StringArray conversion needs no arguments",
3098 (String*) NULL, (Cardinal*) NULL);
3100 delim = ((String) from->addr)[0];
3101 s = XtNewString((String) from->addr + 1);
3102 i = 0;
3103 while (s && *s) {
3104 t = strchr(s, delim);
3105 if (t) *t = '\0';
3106 a = (StringArray) XtRealloc((String) a, (i + 1) * sizeof(*a));
3107 a[i] = s;
3108 i++;
3109 s = t ? t + 1 : NULL;
3111 a = (StringArray) XtRealloc((String) a, (i + 1) * sizeof(*a));
3112 a[i] = NULL;
3113 done_bert(StringArray, a);
3117 /* ***********************************************************************
3118 * A driver for the above in the flavor of the xt utilities module
3119 * ***********************************************************************
3122 #define TABHT 25
3124 typedef struct tab_data {
3125 Widget form;
3126 int cur,
3127 num_tabs;
3128 void (*activate_func)();
3129 } *TabData;
3132 #if defined(__STDC__)
3133 static void handle_click( Widget w, TabData td, XtPointer call_data )
3134 #else
3135 static void handle_click(w, td, call_data)
3136 Widget w;
3137 TabData td;
3138 XtPointer call_data;
3139 #endif
3141 int tab = (int) call_data;
3143 /* note that the tab is relative to the current tab.
3144 * if tab is 0, the user clicked on the current one.
3145 * there is nothing to do
3147 if (tab == 0) return;
3148 td->cur += tab;
3150 /* Change tabs. We must manually inform the UI which tab is current */
3151 XtVaSetValues( w,
3152 XtNlefttabs, td->cur,
3153 XtNrighttabs, td->num_tabs - td->cur - 1,
3154 NULL
3157 (*td->activate_func)( td->form, td->cur );
3162 * PUBLIC: Widget __vi_CreateTabbedFolder
3163 * PUBLIC: __P((String, Widget, String, int, void (*)(Widget, int)));
3165 #if defined(__STDC__)
3166 Widget __vi_CreateTabbedFolder( String name,
3167 Widget parent,
3168 String tab_labels,
3169 int num_tabs,
3170 void (*activate_func)()
3172 #else
3173 Widget __vi_CreateTabbedFolder( name, parent, tab_labels, num_tabs, activate_func )
3174 String name;
3175 String tab_labels;
3176 Widget parent;
3177 int num_tabs;
3178 void (*activate_func)();
3179 #endif
3181 Widget tabs;
3182 TabData td = (TabData) malloc( sizeof(struct tab_data) );
3183 int i;
3185 XtAppSetTypeConverter( XtDisplayToApplicationContext(XtDisplay(parent)),
3186 XtRString,
3187 XtRCardinal,
3188 strtocard,
3189 NULL,
3191 XtCacheNone,
3192 NULL
3195 /* init our internal structure */
3196 td->cur = 0;
3197 td->num_tabs = num_tabs;
3198 td->activate_func = activate_func;
3200 /* tabs go on the top */
3201 tabs = XtVaCreateManagedWidget( "tabs",
3202 xmTabsWidgetClass,
3203 parent,
3204 XtNlefttabs, 0,
3205 XtNrighttabs, num_tabs-1,
3206 XtNorientation, XfwfUpTabs,
3207 XmNtopAttachment, XmATTACH_FORM,
3208 XmNleftAttachment, XmATTACH_FORM,
3209 XmNleftOffset, TABHT/4,
3210 XmNrightAttachment,XmATTACH_FORM,
3211 XmNrightOffset, TABHT/4,
3212 XmNbottomAttachment,XmATTACH_OPPOSITE_FORM,
3213 XmNbottomOffset, -TABHT,
3214 XtNlabels, tab_labels,
3215 XtVaTypedArg, XtNlabels,
3216 XtRString,
3217 tab_labels,
3218 strlen(tab_labels) + 1,
3219 NULL
3222 /* add the callback */
3223 XtAddCallback( tabs,
3224 XtNactivateCallback,
3225 (XtCallbackProc) handle_click,
3229 /* another form to hold the controls */
3230 td->form = XtVaCreateWidget( "form",
3231 xmFormWidgetClass,
3232 parent,
3233 XmNtopAttachment, XmATTACH_WIDGET,
3234 XmNtopWidget, tabs,
3235 XmNleftAttachment, XmATTACH_FORM,
3236 XmNbottomAttachment, XmATTACH_FORM,
3237 XmNrightAttachment, XmATTACH_FORM,
3238 NULL
3241 /* done */
3242 return td->form;