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