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