home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume19 / xfig / part14 / w_rottext.c < prev   
Encoding:
C/C++ Source or Header  |  1993-05-27  |  20.5 KB  |  783 lines

  1. /*
  2.  * FIG : Facility for Interactive Generation of figures
  3.  * Copyright (c) 1992 by Alan Richardson
  4.  *
  5.  * "Permission to use, copy, modify, distribute, and sell this software and its
  6.  * documentation for any purpose is hereby granted without fee, provided that
  7.  * the above copyright notice appear in all copies and that both the copyright
  8.  * notice and this permission notice appear in supporting documentation. 
  9.  * No representations are made about the suitability of this software for 
  10.  * any purpose.  It is provided "as is" without express or implied warranty."
  11.  */
  12.  
  13. #include "fig.h"
  14. #include "w_rottext.h"
  15.  
  16. /* ---------------------------------------------------------------------- */
  17.  
  18. #define XROTMAX(a, b) ((a)>(b)?(a):(b))
  19.  
  20. /* ---------------------------------------------------------------------- */
  21.  
  22. char            *my_strdup();
  23. char            *my_strtok();
  24. XRotFontStruct         *XRotLoadFont();
  25. void              XRotUnloadFont();
  26. int               XRotTextWidth();
  27. int               XRotTextHeight();
  28. void             XRotDrawString();
  29. void               XRotDrawImageString();
  30. void                     XRotPaintString();
  31. void               XRotDrawAlignedString();
  32. void                     XRotDrawAlignedImageString();
  33. void                     XRotPaintAlignedString();
  34.  
  35. /* ---------------------------------------------------------------------- */
  36.   
  37. /* *** Routine to mimic `strdup()' (some machines don't have it) *** */
  38.  
  39. char *my_strdup(str)
  40.  char *str;
  41. {
  42.  char *s;
  43.  
  44.  if(str==NULL) return (char *)NULL;
  45.  
  46.  s=(char *)malloc((unsigned)(strlen(str)+1));
  47.  if(!s)
  48.   { fprintf(stderr, "Error: my_strdup(): Couldn't do malloc\n");
  49.     exit(1); }
  50.  
  51.  strcpy(s, str);
  52.  
  53.  return s;
  54. }
  55.  
  56.  
  57. /* ---------------------------------------------------------------------- */
  58.  
  59.  
  60. /* *** Routine to replace `strtok' : this one returns a zero
  61.        length string if it encounters two consecutive delimiters *** */
  62.  
  63. char *my_strtok(str1, str2)
  64.  char *str1, *str2;
  65. {
  66.  char *ret;
  67.  int i, j, stop;
  68.  static int start, len;
  69.  static char *stext;
  70.  
  71.  if(str2==NULL)
  72.   { fprintf(stderr, "Error: my_strtok(): null delimiter string\n");
  73.     exit(1);
  74.   }
  75.  
  76.  /* initialise if str1 not NULL ... */
  77.  if(str1!=NULL)
  78.   { start=0;
  79.     stext=str1;
  80.     len=strlen(str1);
  81.   }
  82.  
  83.  /* run out of tokens ? ... */
  84.  if(start>=len) return (char *)NULL;
  85.  
  86.  /* loop through characters ... */
  87.  for(i=start; i<len; i++)
  88.  {
  89.   /* loop through delimiters ... */
  90.   stop=0;
  91.   for(j=0; j<strlen(str2); j++) if(stext[i]==str2[j]) stop=1;
  92.  
  93.   if(stop) break;
  94.  }
  95.  
  96.  stext[i]='\0';
  97.  
  98.  ret=stext+start;
  99.  
  100.  start=i+1;
  101.  
  102.  return ret;
  103. }
  104.  
  105.  
  106. /* ---------------------------------------------------------------------- */
  107.   
  108.  
  109. /* *** Load the rotated version of a given font *** */
  110.  
  111. XRotFontStruct *XRotLoadFont(dpy, fontname, angle)
  112.  Display *dpy;
  113.  char *fontname;
  114.  float angle;
  115. {
  116.  char         val;
  117.  XImage        *I1, *I2;
  118.  Pixmap         canvas;
  119.  Window         root;
  120.  int         screen;
  121.  GC         font_gc;
  122.  char         text[3];
  123.  XFontStruct    *fontstruct;
  124.  XRotFontStruct    *rotfont;
  125.  int         ichar, i, j, index, boxlen, dir;
  126.  int         vert_w, vert_h, vert_len, bit_w, bit_h, bit_len;
  127.  int         min_char, max_char;
  128.  unsigned char    *vertdata, *bitdata;
  129.  int         ascent, descent, lbearing, rbearing;
  130.  int         on=1, off=0;
  131.  
  132.  dir=(int)(angle/90.0+0.01);
  133.  if (dir > 3)
  134.     dir -= 4;
  135.  
  136.  /* useful macros ... */
  137.  screen=DefaultScreen(dpy);
  138.  root=DefaultRootWindow(dpy);
  139.  
  140.  /* load the font ... */
  141.  fontstruct=XLoadQueryFont(dpy, fontname);
  142.  if(!fontstruct) { 
  143.     fprintf(stderr,
  144.             "Error: XRotLoadFont(): XServer couldn't load the font `%s'\n",
  145.             fontname);
  146.     exit(1); 
  147.  }
  148.  
  149.  /* boxlen is the square size that would enclose the largest character */
  150.  boxlen = max2(fontstruct->max_bounds.rbearing - fontstruct->max_bounds.lbearing, 
  151.           fontstruct->max_bounds.ascent + fontstruct->max_bounds.descent);
  152.  boxlen *= 2;
  153.  
  154.  /* create the depth 1 canvas bitmap ... */
  155.  canvas=XCreatePixmap(dpy, root, boxlen, boxlen, 1);
  156.  
  157.  /* create a GC ... */
  158.  font_gc=XCreateGC(dpy, canvas, NULL, 0);
  159.  XSetBackground(dpy, font_gc, off);
  160.  
  161.  XSetFont(dpy, font_gc, fontstruct->fid);
  162.  
  163.  /* allocate space for rotated font ... */
  164.  rotfont=(XRotFontStruct *)malloc((unsigned)sizeof(XRotFontStruct));
  165.  if(!rotfont) { 
  166.     fprintf(stderr,"Error: XRotLoadFont(): Couldn't do malloc\n");
  167.     exit(1); 
  168.  }
  169.    
  170.  /* determine which characters are defined in font ... */
  171.  min_char=fontstruct->min_char_or_byte2; 
  172.  max_char=fontstruct->max_char_or_byte2;
  173.  
  174.  /* we only want printing characters ... */
  175.  if(min_char<32)  min_char=32;
  176.  if(max_char>126) max_char=126;
  177.      
  178.  /* some overall font data ... */
  179.  rotfont->name=my_strdup(fontname);
  180.  rotfont->dir=dir;
  181.  rotfont->min_char=min_char;
  182.  rotfont->max_char=max_char;
  183.  rotfont->max_ascent=fontstruct->max_bounds.ascent;
  184.  rotfont->max_descent=fontstruct->max_bounds.descent;   
  185.  rotfont->height=rotfont->max_ascent+rotfont->max_descent;
  186.  rotfont->width=fontstruct->max_bounds.width;
  187.  
  188.  /* remember xfontstruct for `normal' text ... */
  189.  if(dir==0) 
  190.     rotfont->xfontstruct=fontstruct;
  191.  
  192.  /* loop through each character ... */
  193.  for(ichar=min_char; ichar<=max_char; ichar++) {
  194.  
  195.      index=ichar-fontstruct->min_char_or_byte2;
  196.      /* per char dimensions ... */
  197.      ascent=  rotfont->per_char[ichar-32].ascent=
  198.                       fontstruct->per_char[index].ascent;
  199.      descent= rotfont->per_char[ichar-32].descent=
  200.                       fontstruct->per_char[index].descent;
  201.      lbearing=rotfont->per_char[ichar-32].lbearing=
  202.                       fontstruct->per_char[index].lbearing;
  203.      rbearing=rotfont->per_char[ichar-32].rbearing=
  204.                       fontstruct->per_char[index].rbearing;
  205.               rotfont->per_char[ichar-32].width=
  206.                       fontstruct->per_char[index].width;
  207.  
  208.      /* no need for the following with normal text */
  209.      if (dir == 0)
  210.     continue;
  211.  
  212.      /* some space chars have zero body, but a bitmap can't have ... */
  213.      if(!ascent && !descent)   
  214.             ascent=  rotfont->per_char[ichar-32].ascent=  1;
  215.      if(!lbearing && !rbearing) 
  216.             rbearing=rotfont->per_char[ichar-32].rbearing=1;
  217.  
  218.      /* glyph width and height when vertical ... */
  219.      vert_w=rbearing-lbearing;
  220.      vert_h=ascent+descent;
  221.  
  222.      /* width in bytes ... */
  223.      vert_len=(vert_w-1)/8+1;   
  224.  
  225.      XSetForeground(dpy, font_gc, off);
  226.      XFillRectangle(dpy, canvas, font_gc, 0, 0, boxlen, boxlen);
  227.  
  228.      /* draw the character centre top right on canvas ... */
  229.      sprintf(text, "%c", ichar);
  230.      XSetForeground(dpy, font_gc, on);
  231.      XDrawImageString(dpy, canvas, font_gc, boxlen/2-lbearing,
  232.                       boxlen/2-descent, text, 1);
  233.  
  234.      /* reserve memory for first XImage ... */
  235.      vertdata=(unsigned char *) malloc((unsigned)(vert_len*vert_h));
  236.      if(!vertdata) { 
  237.     fprintf(stderr,"Error: XRotLoadFont(): Couldn't do malloc\n");
  238.         exit(1); 
  239.       }
  240.   
  241.      /* create the XImage ... */
  242.      I1=XCreateImage(dpy, DefaultVisual(dpy, screen), 1, XYBitmap,
  243.                      0, (char *) vertdata, vert_w, vert_h, 8, 0);
  244.  
  245.      if(!I1) { 
  246.     fprintf(stderr,"Error: XRotLoadFont(): Couldn't create XImage\n");
  247.         exit(1); 
  248.      }
  249.   
  250.      I1->byte_order=I1->bitmap_bit_order=MSBFirst;
  251.  
  252.      /* extract character from canvas ... */
  253.      XGetSubImage(dpy, canvas, boxlen/2, boxlen/2-vert_h,
  254.                   vert_w, vert_h, 1, XYPixmap, I1, 0, 0);
  255.      I1->format=XYBitmap; 
  256.  
  257.      /* width, height of rotated character ... */
  258.      if(dir==2) { 
  259.     bit_w=vert_w; bit_h=vert_h; 
  260.      } else { 
  261.     bit_w=vert_h; bit_h=vert_w; 
  262.      }
  263.  
  264.      /* width in bytes ... */
  265.      bit_len=(bit_w-1)/8+1;
  266.    
  267.      rotfont->per_char[ichar-32].glyph.bit_w=bit_w;
  268.      rotfont->per_char[ichar-32].glyph.bit_h=bit_h;
  269.  
  270.      /* reserve memory for the rotated image ... */
  271.      bitdata=(unsigned char *)calloc((unsigned)(bit_h*bit_len), 1);
  272.      if(!bitdata) { 
  273.     fprintf(stderr,"Error: XRotLoadFont(): Couldn't do calloc\n");
  274.         exit(1); 
  275.      }
  276.  
  277.      /* create the image ... */
  278.      I2=XCreateImage(dpy, DefaultVisual(dpy, screen), 1, XYBitmap, 0,
  279.                      (char *) bitdata, bit_w, bit_h, 8, 0); 
  280.  
  281.      if(!I2) { 
  282.     fprintf(stderr,"Error: XRotLoadFont(): Couldn't create XImage\n");
  283.         exit(1);
  284.      }
  285.  
  286.      I2->byte_order=I2->bitmap_bit_order=MSBFirst;
  287.  
  288.      /* map vertical data to rotated character ... */
  289.      for(j=0; j<bit_h; j++) {
  290.       for(i=0; i<bit_w; i++) {
  291.        /* map bits ... */
  292.        if(dir==1)
  293.          val=vertdata[i*vert_len + (vert_w-j-1)/8] & (128>>((vert_w-j-1)%8));
  294.    
  295.        else if(dir==2)
  296.          val=vertdata[(vert_h-j-1)*vert_len + (vert_w-i-1)/8] &
  297.                                                        (128>>((vert_w-i-1)%8));
  298.        else 
  299.          val=vertdata[(vert_h-i-1)*vert_len + j/8] & (128>>(j%8));
  300.         
  301.        if(val) bitdata[j*bit_len + i/8] = 
  302.                    bitdata[j*bit_len + i/8]|(128>>(i%8));
  303.       }
  304.      }
  305.    
  306.      /* create this character's bitmap ... */
  307.      rotfont->per_char[ichar-32].glyph.bm=
  308.        XCreatePixmap(dpy, root, bit_w, bit_h, 1);
  309.      
  310.      /* put the image into the bitmap ... */
  311.      XPutImage(dpy, rotfont->per_char[ichar-32].glyph.bm, 
  312.                font_gc, I2, 0, 0, 0, 0, bit_w, bit_h);
  313.   
  314.      /* free the image and data ... */
  315.      XDestroyImage(I1);
  316.      XDestroyImage(I2);
  317.      free((char *)bitdata);
  318.      free((char *)vertdata);
  319.  }
  320.  
  321.  if (dir != 0)
  322.     XFreeFont(dpy, fontstruct);
  323.  
  324.  /* free pixmap and GC ... */
  325.  XFreePixmap(dpy, canvas);
  326.  XFreeGC(dpy, font_gc);
  327.  
  328.  return rotfont;
  329. }
  330.  
  331.  
  332. /* ---------------------------------------------------------------------- */
  333.  
  334.  
  335. /* *** Free the resources associated with a rotated font *** */
  336.  
  337. void XRotUnloadFont(dpy, rotfont)
  338.  Display *dpy;
  339.  XRotFontStruct *rotfont;
  340. {
  341.  int ichar;
  342.  
  343.  if(rotfont->dir==0) XFreeFont(dpy, rotfont->xfontstruct);
  344.  
  345.  else
  346.   /* loop through each character, freeing its pixmap ... */
  347.   for(ichar=rotfont->min_char-32; ichar<=rotfont->max_char-32; ichar++)
  348.     XFreePixmap(dpy, rotfont->per_char[ichar].glyph.bm);
  349.  
  350.  /* rotfont should never be referenced again ... */
  351.  free((char *)rotfont);
  352. }
  353.  
  354.  
  355. /* ---------------------------------------------------------------------- */
  356.    
  357.  
  358. /* *** Return the width of a string *** */
  359.  
  360. int XRotTextWidth(rotfont, str, len)
  361.  XRotFontStruct *rotfont;
  362.  char *str;
  363.  int len;
  364. {
  365.  int i, width=0, ichar;
  366.  
  367.  if(str==NULL) 
  368.     return 0;
  369.  
  370.  if(rotfont->dir==0)
  371.     width=XTextWidth(rotfont->xfontstruct, str, len);
  372.  
  373.  else
  374.   for(i=0; i<len; i++) {
  375.    ichar=str[i]-32;
  376.   
  377.    /* make sure it's a printing character ... */
  378.    if((ichar>=0)&&(ichar<95)) 
  379.     width+=rotfont->per_char[ichar].width;
  380.   }
  381.  
  382.  return width;
  383. }
  384.  
  385. /* *** Return the height of a string *** */
  386.  
  387. int XRotTextHeight(rotfont, str, len)
  388.  XRotFontStruct *rotfont;
  389.  char *str;
  390.  int len;
  391. {
  392.  int i, height=0, ichar;
  393.  int maxasc=0;
  394.  int maxdsc=0;
  395.  int dum;
  396.  XCharStruct ch;
  397.  
  398.  if(str==NULL) return 0;
  399.  
  400.  if(rotfont->dir==0) {
  401.     XTextExtents(rotfont->xfontstruct, str, len, &dum,&dum,&dum,&ch);
  402.     height = ch.ascent + ch.descent;
  403.  }
  404.  else
  405.   for(i=0; i<len; i++)
  406.   {
  407.    ichar=str[i]-32;
  408.   
  409.    /* make sure it's a printing character ... */
  410.    /* then find the highest and most descending */
  411.    if((ichar>=0)&&(ichar<95)) {
  412.     maxasc=max2(maxasc,rotfont->per_char[ichar].ascent);
  413.     maxdsc=max2(maxdsc,rotfont->per_char[ichar].descent);
  414.    }
  415.    /* and add the two together */
  416.    height = maxasc+maxdsc;
  417.   }
  418.  
  419.  return height;
  420. }
  421.  
  422.  
  423. /* ---------------------------------------------------------------------- */
  424.  
  425.  
  426. /* *** A front end to XRotPaintString : mimics XDrawString *** */
  427.  
  428. void XRotDrawString(dpy,  drawable, rotfont,gc, x, y, str, len)
  429.  Display *dpy;
  430.  Drawable drawable;
  431.  XRotFontStruct *rotfont;
  432.  GC gc;
  433.  int x, y;
  434.  char *str;
  435.  int len;
  436. {
  437.  XRotPaintString(dpy, drawable, rotfont, gc, x, y, str, len, 0);
  438. }
  439.  
  440.  
  441. /* ---------------------------------------------------------------------- */
  442.  
  443.  
  444. /* *** A front end to XRotPaintString : mimics XDrawImageString *** */
  445.  
  446. void XRotDrawImageString(dpy,  drawable, rotfont, gc, x, y, str, len)
  447.  Display *dpy;
  448.  Drawable drawable;
  449.  XRotFontStruct *rotfont;
  450.  GC gc;
  451.  int x, y;
  452.  char *str;
  453.  int len;
  454. {
  455.  XRotPaintString(dpy, drawable, rotfont, gc, x, y, str, len, 1);
  456. }
  457.  
  458.  
  459. /* ---------------------------------------------------------------------- */
  460.               
  461.               
  462. /* *** Paint a simple string with a rotated font *** */
  463.  
  464. /* *** The user should use one of the two front ends above *** */
  465.  
  466. void XRotPaintString(dpy,  drawable, rotfont, gc, x, y, str, len, paintbg)
  467.  Display *dpy;
  468.  Drawable drawable;
  469.  XRotFontStruct *rotfont;
  470.  GC gc;
  471.  int x, y;
  472.  char *str;
  473.  int len;
  474.  int paintbg;
  475. {            
  476.  static GC my_gc=NULL;
  477.  XGCValues values;
  478.  int i, xp, yp, dir, ichar, width;
  479. #ifdef X11R3
  480.  static Pixmap empty_stipple=(Pixmap)NULL;
  481. #endif
  482.  
  483.  dir=rotfont->dir;
  484.  
  485.  if(!my_gc) my_gc=XCreateGC(dpy, drawable, NULL, 0);
  486.  
  487.  XCopyGC(dpy, gc, GCFunction|GCForeground|GCBackground, my_gc);
  488.  
  489.  /* a horizontal string is easy ... */
  490.  if(dir==0)
  491.   { XSetFillStyle(dpy, my_gc, FillSolid);
  492.     XSetFont(dpy, my_gc, rotfont->xfontstruct->fid);
  493.     if(!paintbg) XDrawString(dpy, drawable, my_gc, x, y, str, len);
  494.     else         XDrawImageString(dpy, drawable, my_gc, x, y, str, len);
  495.  
  496.     return;
  497.   }
  498.  
  499.  /* vertical or upside down ... */
  500.  
  501.  /* to draw an `image string' we need to fill the background ... */
  502.  if(paintbg)
  503.   {
  504. #ifdef X11R3
  505.    /* Release 3 doesn't have XGetGCValues(), so this is a
  506.       slightly slower fudge ... */
  507.    {
  508.     GC stipple_gc;
  509.     int bestw, besth;
  510.  
  511.     if(!empty_stipple)    
  512.      { XQueryBestStipple(dpy, drawable, 1, 1, &bestw, &besth);
  513.        empty_stipple=XCreatePixmap(dpy, drawable, bestw, besth, 1);
  514.  
  515.        stipple_gc=XCreateGC(dpy, empty_stipple, NULL, 0);
  516.        XSetForeground(dpy, stipple_gc, 0);
  517.  
  518.        XFillRectangle(dpy, empty_stipple, stipple_gc, 0, 0, bestw+1, besth+1);
  519.        XFreeGC(dpy, stipple_gc);
  520.      }
  521.  
  522.      XSetStipple(dpy, my_gc, empty_stipple);
  523.      XSetFillStyle(dpy, my_gc, FillOpaqueStippled);
  524.    }    
  525. #else
  526.    /* get the foreground and background colors
  527.         ( note that this is not a round trip -> little speed penalty ) */
  528.    XGetGCValues(dpy, my_gc, GCForeground|GCBackground, &values);
  529.  
  530.    XSetForeground(dpy, my_gc, values.background);
  531.    XSetFillStyle(dpy, my_gc, FillSolid);
  532. #endif
  533.  
  534.    width=XRotTextWidth(rotfont, str, strlen(str));
  535.  
  536.    if(dir==1)
  537.      XFillRectangle(dpy, drawable, my_gc, x-rotfont->max_ascent+1, y-width,
  538.                     rotfont->height-1, width);
  539.    else if(dir==2)
  540.      XFillRectangle(dpy, drawable, my_gc, x-width, y-rotfont->max_descent+1,
  541.                     width, rotfont->height-1);
  542.    else
  543.      XFillRectangle(dpy, drawable, my_gc, x-rotfont->max_descent+1,
  544.                     y, rotfont->height-1, width);
  545.  
  546. #ifndef X11R3
  547.    XSetForeground(dpy, my_gc, values.foreground);
  548. #endif
  549.   }
  550.  
  551.  XSetFillStyle(dpy, my_gc, FillStippled);
  552.  
  553.  /* loop through each character in string ... */
  554.  for(i=0; i<len; i++)
  555.  {
  556.   ichar=str[i]-32;
  557.  
  558.   /* make sure it's a printing character ... */
  559.   if((ichar>=0)&&(ichar<95))
  560.   {
  561.    /* suitable offset ... */
  562.    if(dir==1)
  563.      { xp=x-rotfont->per_char[ichar].ascent;
  564.        yp=y-rotfont->per_char[ichar].rbearing; }
  565.    else if(dir==2)
  566.      { xp=x-rotfont->per_char[ichar].rbearing;
  567.        yp=y-rotfont->per_char[ichar].descent+1; }
  568.    else
  569.      { xp=x-rotfont->per_char[ichar].descent+1;  
  570.        yp=y+rotfont->per_char[ichar].lbearing; }
  571.                    
  572.    /* draw the glyph ... */
  573.    XSetStipple(dpy, my_gc, rotfont->per_char[ichar].glyph.bm);
  574.  
  575.    XSetTSOrigin(dpy, my_gc, xp, yp);
  576.    
  577.    XFillRectangle(dpy, drawable, my_gc, xp, yp,
  578.                   rotfont->per_char[ichar].glyph.bit_w,
  579.                   rotfont->per_char[ichar].glyph.bit_h);
  580.     
  581.    /* advance position ... */
  582.    if(dir==1)      y-=rotfont->per_char[ichar].width;
  583.    else if(dir==2) x-=rotfont->per_char[ichar].width;
  584.    else            y+=rotfont->per_char[ichar].width;
  585.   }
  586.  }
  587. }
  588.   
  589.     
  590. /* ---------------------------------------------------------------------- */
  591.  
  592.  
  593. /* *** A front end to XRotPaintAlignedString : uses XRotDrawString *** */
  594.  
  595. void XRotDrawAlignedString(dpy, drawable, rotfont, gc, x, y,
  596.                                   text, align)
  597.  Display *dpy;                    
  598.  Drawable drawable;
  599.  XRotFontStruct *rotfont;
  600.  GC gc;
  601.  int x, y;
  602.  char *text;
  603.  int align;
  604. {
  605.  XRotPaintAlignedString(dpy, drawable, rotfont, gc, x, y, text, align, 0);
  606. }
  607.  
  608.  
  609. /* ---------------------------------------------------------------------- */
  610.  
  611.  
  612. /* *** A front end to XRotPaintAlignedString : uses XRotDrawImageString *** */
  613.  
  614. void XRotDrawAlignedImageString(dpy, drawable, rotfont, gc, x, y,
  615.                                   text, align)
  616.  Display *dpy;
  617.  Drawable drawable;  
  618.  XRotFontStruct *rotfont;
  619.  GC gc;
  620.  int x, y;
  621.  char *text;
  622.  int align;
  623. {
  624.  XRotPaintAlignedString(dpy, drawable, rotfont, gc, x, y, text, align, 1);
  625. }
  626.  
  627.  
  628. /* ---------------------------------------------------------------------- */
  629.                    
  630.                    
  631. /* *** Routine to paint a string, possibly containing newline characters,
  632.                                                        with alignment *** */
  633.  
  634. /* *** The user should use one of the front ends above *** */
  635.  
  636. void XRotPaintAlignedString(dpy, drawable, rotfont, gc, x, y, text,
  637.                             align, paintbg)
  638.  Display *dpy;
  639.  Drawable drawable;
  640.  XRotFontStruct *rotfont;
  641.  GC gc;
  642.  int x, y;
  643.  char *text;
  644.  int align;
  645.  int paintbg;
  646. {  
  647.  int xp, yp, dir;
  648.  int i, nl=1, max_width=0, this_width;
  649.  char *str1, *str2="\n\0", *str3;
  650.  
  651.  if(text==NULL) return;
  652.   
  653.  dir=rotfont->dir;
  654.  
  655.  /* count number of sections in string ... */
  656.  for(i=0; i<strlen(text); i++) if(text[i]=='\n') nl++;
  657.  
  658.  /* find width of longest section ... */
  659.  str1=my_strdup(text);
  660.  str3=my_strtok(str1, str2);
  661.  max_width=XRotTextWidth(rotfont, str3, strlen(str3));
  662.  
  663.  do
  664.   { str3=my_strtok((char *)NULL, str2);
  665.     if(str3)
  666.       max_width=XROTMAX(max_width,
  667.                         XRotTextWidth(rotfont, str3, strlen(str3))); }
  668.  while(str3!=NULL);
  669.  
  670.  /* calculate vertical starting point according to alignment policy and
  671.       rotation angle ... */
  672.  if(dir==0)
  673.  { if((align==TLEFT)||(align==TCENTRE)||(align==TRIGHT))
  674.      yp=y+rotfont->max_ascent;
  675.  
  676.   else if((align==BLEFT)||(align==BCENTRE)||(align==BRIGHT))
  677.      yp=y-(nl-1)*rotfont->height - rotfont->max_descent;
  678.  
  679.   else 
  680.      yp=y-(nl-1)/2*rotfont->height + rotfont->max_ascent -rotfont->height/2 -
  681.                          ( (nl%2==0)?rotfont->height/2:0 ); }
  682.  
  683.  else if(dir==1)
  684.  { if((align==TLEFT)||(align==TCENTRE)||(align==TRIGHT))
  685.      xp=x+rotfont->max_ascent;
  686.  
  687.    else if((align==BLEFT)||(align==BCENTRE)||(align==BRIGHT))
  688.      xp=x-(nl-1)*rotfont->height - rotfont->max_descent;
  689.  
  690.    else 
  691.      xp=x-(nl-1)/2*rotfont->height + rotfont->max_ascent -rotfont->height/2 -
  692.                          ( (nl%2==0)?rotfont->height/2:0 ); }
  693.  
  694.  else if(dir==2)
  695.  { if((align==TLEFT)||(align==TCENTRE)||(align==TRIGHT))
  696.      yp=y-rotfont->max_ascent;
  697.      
  698.    else if((align==BLEFT)||(align==BCENTRE)||(align==BRIGHT))
  699.      yp=y+(nl-1)*rotfont->height + rotfont->max_descent;
  700.      
  701.    else 
  702.      yp=y+(nl-1)/2*rotfont->height - rotfont->max_ascent +rotfont->height/2 +
  703.                          ( (nl%2==0)?rotfont->height/2:0 ); }
  704.  
  705.  else
  706.  { if((align==TLEFT)||(align==TCENTRE)||(align==TRIGHT))
  707.      xp=x-rotfont->max_ascent;
  708.     
  709.    else if((align==BLEFT)||(align==BCENTRE)||(align==BRIGHT))
  710.      xp=x+(nl-1)*rotfont->height + rotfont->max_descent;
  711.   
  712.    else 
  713.      xp=x+(nl-1)/2*rotfont->height - rotfont->max_ascent +rotfont->height/2 +
  714.                          ( (nl%2==0)?rotfont->height/2:0 ); }
  715.  
  716.  str1=my_strdup(text);
  717.  str3=my_strtok(str1, str2);
  718.   
  719.  /* loop through each section in the string ... */
  720.  do
  721.  {
  722.   /* width of this section ... */
  723.   this_width=XRotTextWidth(rotfont, str3, strlen(str3));
  724.  
  725.   /* horizontal alignment ... */
  726.   if(dir==0)
  727.   { if((align==TLEFT)||(align==MLEFT)||(align==BLEFT))
  728.       xp=x;
  729.   
  730.     else if((align==TCENTRE)||(align==MCENTRE)||(align==BCENTRE))
  731.       xp=x-this_width/2;
  732.  
  733.     else 
  734.       xp=x-max_width; }
  735.  
  736.   else if(dir==1)
  737.   { if((align==TLEFT)||(align==MLEFT)||(align==BLEFT))
  738.       yp=y;
  739.  
  740.     else if((align==TCENTRE)||(align==MCENTRE)||(align==BCENTRE))
  741.       yp=y+this_width/2;
  742.  
  743.     else 
  744.       yp=y+max_width; }
  745.  
  746.   else if(dir==2)
  747.   { if((align==TLEFT)||(align==MLEFT)||(align==BLEFT))
  748.       xp=x;
  749.   
  750.     else if((align==TCENTRE)||(align==MCENTRE)||(align==BCENTRE))
  751.       xp=x+this_width/2;
  752.  
  753.     else 
  754.       xp=x+max_width; }
  755.  
  756.   else
  757.   { if((align==TLEFT)||(align==MLEFT)||(align==BLEFT))  
  758.       yp=y;
  759.      
  760.     else if((align==TCENTRE)||(align==MCENTRE)||(align==BCENTRE))
  761.       yp=y-this_width/2;
  762.      
  763.     else 
  764.       yp=y-max_width; }
  765.  
  766.   /* draw the section ... */
  767.   if(!paintbg)  XRotDrawString(dpy, drawable, rotfont, gc, xp, yp,
  768.                                str3, strlen(str3));
  769.   else          XRotDrawImageString(dpy, drawable, rotfont, gc, xp, yp, 
  770.                                str3, strlen(str3));  
  771.  
  772.   str3=my_strtok((char *)NULL, str2);
  773.  
  774.   /* advance position ... */
  775.   if(dir==0)      yp+=rotfont->height;
  776.   else if(dir==1) xp+=rotfont->height;
  777.   else if(dir==2) yp-=rotfont->height;
  778.   else            xp-=rotfont->height;
  779.  }
  780.  while(str3!=NULL);
  781. }
  782.  
  783.