Add library xft for allowing text rotation.

Setting variabe 'old_x11' will retain previous behaviour.
This commit is contained in:
h_vogt 2017-10-04 15:35:03 +02:00 committed by Holger Vogt
parent 0cdea87cb5
commit 531c229b0e
1 changed files with 152 additions and 36 deletions

View File

@ -14,6 +14,7 @@ Author: 1988 Jeffrey M. Hsu
# include <sys/time.h>
# include <sys/types.h> /* PN */
# include <unistd.h> /* PN */
# include <locale.h>
# include "ngspice/graph.h"
# include "ngspice/ftedbgra.h"
@ -37,6 +38,8 @@ Author: 1988 Jeffrey M. Hsu
# include <X11/Shell.h>
# include <X11/Intrinsic.h>
#include <X11/Xft/Xft.h>
# ifdef DEBUG
# include <X11/Xlib.h> /* for _Xdebug */
# endif
@ -66,6 +69,11 @@ typedef struct x11info {
int lastx, lasty; /* used in X_DrawLine */
int lastlinestyle; /* used in X_DrawLine */
Pixel colors[NUMCOLORS];
/* use with xft */
char txtcolor[16];
char bgcolor[16];
char fname[BSIZE_SP];
int fsize;
} X11devdep;
#define DEVDEP(g) (*((X11devdep *) (g)->devdep))
@ -91,6 +99,8 @@ static Bool noclear = False;
static GRAPH *lasthardcopy; /* graph user selected */
static int X11_Open = 0;
static int numdispplanes;
static int xfont_size;
static char fontname[513];
/* static functions */
static void initlinestyles(void);
@ -99,6 +109,7 @@ static void X_ScreentoData(GRAPH *graph, int x, int y, double *fx, double *fy);
static void linear_arc(int x0, int y0, int radius, double theta, double delta_theta);
static void slopelocation(GRAPH *graph, int x0, int y0);
static void zoomin(GRAPH *graph);
static int Xget_str_length(char *text, int* wlen, int* wheight, XftFont* gfont, char* name, int fsize);
//XtEventHandler
static void handlekeypressed(Widget w, XtPointer clientdata, XEvent *ev, Boolean *continue_dispatch);
@ -139,6 +150,9 @@ X11_Init(void)
return (1);
}
if (cp_getvar("old_x11", CP_BOOL, NULL))
old_x11 = TRUE;
# ifdef DEBUG
_Xdebug = 1;
# endif
@ -149,9 +163,11 @@ X11_Init(void)
argv[2] = "-geometry";
argv[3] = "=1x1+2+2";
*/
/* initialze internationalization (i18n) */
XtSetLanguageProc(NULL, NULL, NULL);
/* initialize X toolkit */
toplevel = XtInitialize("ngspice", "Nutmeg", NULL, 0, &argc, argv);
setlocale(LC_NUMERIC, "C");
display = XtDisplay(toplevel);
@ -235,6 +251,12 @@ initcolors(GRAPH *graph)
(void) sprintf(buf, "color%d", i);
if (!cp_getvar(buf, CP_STRING, colorstring, sizeof(colorstring)))
(void) strcpy(colorstring, colornames[i]);
/* text color info for xft */
if((!old_x11) && (i == 1))
strncpy(DEVDEP(graph).txtcolor, colorstring, 15);
else if((!old_x11) && (i == 0))
strncpy(DEVDEP(graph).bgcolor, colorstring, 15);
if (!XAllocNamedColor(display,
DefaultColormap(display, DefaultScreen(display)),
colorstring, &visualcolor, &exactcolor)) {
@ -348,7 +370,7 @@ handle_wm_messages(Widget w, XtPointer client_data, XEvent *ev, Boolean *cont)
int
X11_NewViewport(GRAPH *graph)
{
char fontname[513]; /* who knows . . . */
// char fontname[513]; /* who knows . . . */
char *p, *q;
Cursor cursor;
XSetWindowAttributes w_attrs;
@ -376,8 +398,8 @@ X11_NewViewport(GRAPH *graph)
};
static Arg viewargs[] = {
{ XtNresizable, (XtArgVal) TRUE },
{ XtNwidth, (XtArgVal) 300 },
{ XtNheight, (XtArgVal) 300 },
{ XtNwidth, (XtArgVal) 600 },
{ XtNheight, (XtArgVal) 500 },
{ XtNright, (XtArgVal) XtChainRight }
};
int trys;
@ -389,6 +411,7 @@ X11_NewViewport(GRAPH *graph)
DEVDEP(graph).shell = XtCreateApplicationShell
("shell", topLevelShellWidgetClass, NULL, 0);
XtVaSetValues(DEVDEP(graph).shell, XtNtitleEncoding, XInternAtom(display, "UTF8_STRING", False), NULL);
XtVaSetValues(DEVDEP(graph).shell, XtNtitle, graph->plotname, NULL);
/* set up form widget */
@ -428,32 +451,47 @@ X11_NewViewport(GRAPH *graph)
/* set up fonts */
if (!cp_getvar("xfont", CP_STRING, fontname, sizeof(fontname)))
(void) strcpy(fontname, DEF_FONT);
strncpy(DEVDEP(graph).fname, fontname, BSIZE_SP - 1);
for (p = fontname; *p && *p <= ' '; p++)
;
if (p != fontname) {
for (q = fontname; *p; *q++ = *p++)
if(old_x11) {
for (p = fontname; *p && *p <= ' '; p++)
;
*q = '\0';
}
trys = 1;
while (!(DEVDEP(graph).font = XLoadQueryFont(display, fontname))) {
sprintf(ErrorMessage, "can't open font %s", fontname);
strcpy(fontname, "fixed");
if (trys > 1) {
internalerror(ErrorMessage);
RECOVERNEWVIEWPORT();
return (1);
if (p != fontname) {
for (q = fontname; *p; *q++ = *p++)
;
*q = '\0';
}
trys = 1;
while (!(DEVDEP(graph).font = XLoadQueryFont(display, fontname))) {
sprintf(ErrorMessage, "can't open font %s", fontname);
strcpy(fontname, "fixed");
if (trys > 1) {
internalerror(ErrorMessage);
RECOVERNEWVIEWPORT();
return (1);
}
trys += 1;
}
trys += 1;
}
graph->fontwidth = DEVDEP(graph).font->max_bounds.rbearing -
DEVDEP(graph).font->min_bounds.lbearing + 1;
graph->fontheight = DEVDEP(graph).font->max_bounds.ascent +
DEVDEP(graph).font->max_bounds.descent + 1;
/* font size */
if (!cp_getvar("xfont_size", CP_NUM, &xfont_size))
xfont_size = 16;
if(old_x11) {
graph->fontwidth = DEVDEP(graph).font->max_bounds.rbearing -
DEVDEP(graph).font->min_bounds.lbearing + 1;
graph->fontheight = DEVDEP(graph).font->max_bounds.ascent +
DEVDEP(graph).font->max_bounds.descent + 1;
}
else {
int wl, wh;
Xget_str_length("ABCD", &wl, &wh, NULL, fontname, xfont_size);
graph->fontwidth = (int)(wl / 4);
graph->fontheight = wh;
DEVDEP(graph).fsize = xfont_size;
}
XtRealizeWidget(DEVDEP(graph).shell);
@ -462,13 +500,19 @@ X11_NewViewport(GRAPH *graph)
w_attrs.bit_gravity = ForgetGravity;
XChangeWindowAttributes(display, DEVDEP(graph).window, CWBitGravity,
&w_attrs);
/* have to note font and set mask GCFont in XCreateGC, p.w.h. */
gcvalues.font = DEVDEP(graph).font->fid;
gcvalues.line_width = MW_LINEWIDTH;
gcvalues.cap_style = CapNotLast;
gcvalues.function = GXcopy;
DEVDEP(graph).gc = XCreateGC(display, DEVDEP(graph).window,
if (old_x11) {
gcvalues.font = DEVDEP(graph).font->fid;
DEVDEP(graph).gc = XCreateGC(display, DEVDEP(graph).window,
GCFont | GCLineWidth | GCCapStyle | GCFunction, &gcvalues);
}
else
DEVDEP(graph).gc = XCreateGC(display, DEVDEP(graph).window,
GCLineWidth | GCCapStyle | GCFunction, &gcvalues);
/* should absolute.positions really be shell.pos? */
graph->absolute.xpos = DEVDEP(graph).view->core.x;
@ -483,6 +527,7 @@ X11_NewViewport(GRAPH *graph)
cursor = XCreateFontCursor(display, XC_left_ptr);
XDefineCursor(display, DEVDEP(graph).window, cursor);
/* WM_DELETE_WINDOW protocol */
atom_wm_protocols = XInternAtom(display, "WM_PROTOCOLS", False);
atom_wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);
@ -554,16 +599,59 @@ X11_Text(char *text, int x, int y, int angle)
{
/* We specify text position by lower left corner, so have to adjust for
X11's font nonsense. */
NG_IGNORE(angle);
if (DEVDEP(currentgraph).isopen)
XDrawString(display, DEVDEP(currentgraph).window,
DEVDEP(currentgraph).gc, x,
currentgraph->absolute.height
- (y + DEVDEP(currentgraph).font->max_bounds.descent),
text, (int) strlen(text));
int wlen = 0, wheight = 0;
/* note: unlike before, we do not save any text here */
if(old_x11) {
if (DEVDEP(currentgraph).isopen)
XDrawString(display, DEVDEP(currentgraph).window,
DEVDEP(currentgraph).gc, x,
currentgraph->absolute.height
- (y + DEVDEP(currentgraph).font->max_bounds.descent),
text, (int) strlen(text));
/* note: unlike before, we do not save any text here */
return 0;
}
/* new font selection with rotation */
XftPattern *new_pat = XftPatternCreate(); // the pattern we will use for rotating
XftPatternAddString(new_pat, XFT_FAMILY, DEVDEP(currentgraph).fname);
XftPatternAddDouble (new_pat, XFT_PIXEL_SIZE, (double)DEVDEP(currentgraph).fsize);
if(angle != 0){
XftMatrix m;
XftMatrixInit(&m);
XftMatrixRotate(&m,cos(M_PI*angle/180.),sin(M_PI*angle/180.));
XftPatternAddMatrix (new_pat, XFT_MATRIX,&m);
}
XftResult rot_result;
XftPattern *rot_pat = XftFontMatch(display, 0, new_pat, &rot_result); /* do not destroy!*/
XftFont *new_font = XftFontOpenPattern(display, rot_pat);
XftPatternDestroy(new_pat);
/* calculate and add offset, if ylabel with angle 90° */
if (angle == 90) {
Xget_str_length(text, &wlen, &wheight, new_font, NULL, 0);
}
Colormap cmap = DefaultColormap(display, 0);
XftColor color;
XftColorAllocName(display, DefaultVisual(display, 0), cmap, DEVDEP(currentgraph).txtcolor, &color);
XftDraw* draw = XftDrawCreate(
display, DEVDEP(currentgraph).window, DefaultVisual(display, 0), cmap
);
/* Draw text */
XftDrawStringUtf8(
draw, &color, new_font,
x + (int)(1.5 * wlen), currentgraph->absolute.height - y + (int)(0.5 * wheight), (FcChar8*)text, strlen(text)
);
XftFontClose( display, new_font);
XftDrawDestroy(draw);
XftColorFree(display, DefaultVisual(display, 0), cmap, &color);
return 0;
}
@ -828,8 +916,9 @@ zoomin(GRAPH *graph)
"setplot %s; %s xlimit %.20e %.20e ylimit %.20e %.20e; setplot $curplot\n",
buf2, graph->commandline, fx0, fx1, fy0, fy1);
} else {
(void) sprintf(buf, "%s xlimit %e %e ylimit %e %e\n",
graph->commandline, fx0, fx1, fy0, fy1);
/* set the foreground and background colors to the "calling" window's colors */
(void) sprintf(buf, "set color0=%s; set color1=%s; %s xlimit %e %e ylimit %e %e\n",
DEVDEP(graph).bgcolor, DEVDEP(graph).txtcolor, graph->commandline, fx0, fx1, fy0, fy1);
}
/* don't use the following if using GNU Readline or BSD EditLine */
@ -906,7 +995,8 @@ void RemoveWindow(GRAPH *graph)
/* MW. Not sure but DestroyGraph might free() too much - try Xt...() first */
XtUnmapWidget(DEVDEP(graph).shell);
XtDestroyWidget(DEVDEP(graph).shell);
XFreeFont(display, DEVDEP(graph).font);
if (old_x11)
XFreeFont(display, DEVDEP(graph).font);
XFreeGC(display, DEVDEP(graph).gc);
}
@ -1105,6 +1195,32 @@ linear_arc(int x0, int y0, int radius, double theta, double delta_theta)
}
}
/* After font selection for XftTextExtentsUtf8
* to measure character string length.
* Same as rotation below, but 0° angle */
static int
Xget_str_length(char *text, int* wlen, int* wheight, XftFont* gfont, char* foname, int fsize) {
XGlyphInfo extents;
XftFont* hfont = NULL;
/* if font name and font size are given */
if (gfont == NULL) {
XftPattern *ext_pat = XftPatternCreate(); // the pattern we will use for rotating
XftPatternAddString(ext_pat, XFT_FAMILY, foname);
XftPatternAddDouble(ext_pat, XFT_PIXEL_SIZE, (double)fsize);
XftResult ext_result;
hfont = gfont = XftFontOpenPattern(display, XftFontMatch(display, 0, ext_pat, &ext_result));
XftTextExtentsUtf8(display, gfont, (XftChar8 *)text, strlen(text), &extents);
XftPatternDestroy(ext_pat);
}
XftTextExtentsUtf8( display, gfont, (XftChar8 *)text, strlen(text), &extents );
if(hfont)
XftFontClose( display,hfont);
/* size of the string */
*wlen = extents.width;
*wheight = extents.height;
return 0;
}
#else