ngspice/xgraph/xgX.c

481 lines
13 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Generic Output Driver for X
* X version 11
*
* This is the primary output driver used by the new X graph
* to display output to the X server. It has been factored
* out of the original xgraph to allow mulitple hardcopy
* output devices to share xgraph's capabilities. Note:
* xgraph is still heavily X oriented. This is not intended
* for porting to other window systems.
*/
#include "copyright.h"
#include "xgout.h"
#include "params.h"
#define PADDING 2
#define SPACE 10
#define TICKLENGTH 5
#define MAXSEGS 1000
struct x_state {
Window win; /* Primary window */
};
void text_X();
void seg_X();
void dot_X();
typedef struct attr_set {
char lineStyle[MAXLS];
int lineStyleLen;
Pixel pixelValue;
Pixmap markStyle;
} AttrSet;
static AttrSet AllAttrs[MAXATTR];
static Pixmap dotMap = (Pixmap) 0;
/*
* Marker bitmaps
*/
#include "bitmaps/dot.11"
#include "bitmaps/mark1.11"
#include "bitmaps/mark2.11"
#include "bitmaps/mark3.11"
#include "bitmaps/mark4.11"
#include "bitmaps/mark5.11"
#include "bitmaps/mark6.11"
#include "bitmaps/mark7.11"
#include "bitmaps/mark8.11"
/* Sizes exported for marker drawing */
static unsigned int dot_w = dot_width;
static unsigned int dot_h = dot_height;
static unsigned int mark_w = mark1_width;
static unsigned int mark_h = mark1_height;
static int mark_cx = mark1_x_hot;
static int mark_cy = mark1_y_hot;
void
set_X(new_win, out_info)
Window new_win; /* Newly created window */
xgOut *out_info; /* Information to set */
/*
* Sets some of the common parameters for the X output device.
*/
{
struct x_state *new_state;
XFontStruct *font;
out_info->dev_flags = ((depth > 3) ? D_COLOR : 0);
out_info->area_w = out_info->area_h = 0; /* Set later */
out_info->bdr_pad = PADDING;
out_info->axis_pad = SPACE;
out_info->legend_pad = 0;
out_info->tick_len = TICKLENGTH;
font = PM_FONT("LabelFont");
#ifdef OLD
out_info->axis_width =
font->max_bounds.rbearing - font->max_bounds.lbearing;
#endif
out_info->axis_width = XTextWidth(font, "8", 1);
out_info->axis_height =
font->max_bounds.ascent + font->max_bounds.descent;
font = PM_FONT("TitleFont");
#ifdef OLD
out_info->title_width =
font->max_bounds.rbearing - font->max_bounds.lbearing;
#endif
out_info->title_width = XTextWidth(font, "8", 1);
out_info->title_height =
font->max_bounds.ascent + font->max_bounds.descent;
out_info->max_segs = MAXSEGS;
out_info->xg_text = text_X;
out_info->xg_seg = seg_X;
out_info->xg_dot = dot_X;
out_info->xg_end = (void (*) ()) 0;
new_state = (struct x_state *) Malloc(sizeof(struct x_state));
new_state->win = new_win;
out_info->user_state = (char *) new_state;
}
static void
init_once()
/*
* Initializes AllAttrs.
*/
{
Window temp_win;
XSetWindowAttributes wattr;
char name[1024];
int idx;
params style_val;
/* Get attributes out parameters database */
for (idx = 0; idx < MAXATTR; idx++) {
(void) sprintf(name, "%d.Style", idx);
(void) param_get(name, &style_val);
AllAttrs[idx].lineStyleLen = style_val.stylev.len;
(void) strncpy(AllAttrs[idx].lineStyle, style_val.stylev.dash_list,
style_val.stylev.len);
(void) sprintf(name, "%d.Color", idx);
AllAttrs[idx].pixelValue = PM_PIXEL(name);
}
/* Create a temporary window for representing depth */
temp_win = XCreateWindow(disp, RootWindow(disp, screen),
0, 0, 10, 10, 0, depth, InputOutput,
vis, (unsigned long) 0, &wattr);
/* Store bitmaps for dots and markers */
dotMap = XCreateBitmapFromData(disp, temp_win, dot_bits, dot_w, dot_h);
AllAttrs[0].markStyle = XCreateBitmapFromData(disp, temp_win,
mark1_bits, mark_w, mark_h);
AllAttrs[1].markStyle = XCreateBitmapFromData(disp, temp_win,
mark2_bits, mark_w, mark_h);
AllAttrs[2].markStyle = XCreateBitmapFromData(disp, temp_win,
mark3_bits, mark_w, mark_h);
AllAttrs[3].markStyle = XCreateBitmapFromData(disp, temp_win,
mark4_bits, mark_w, mark_h);
AllAttrs[4].markStyle = XCreateBitmapFromData(disp, temp_win,
mark5_bits, mark_w, mark_h);
AllAttrs[5].markStyle = XCreateBitmapFromData(disp, temp_win,
mark6_bits, mark_w, mark_h);
AllAttrs[6].markStyle = XCreateBitmapFromData(disp, temp_win,
mark7_bits, mark_w, mark_h);
AllAttrs[7].markStyle = XCreateBitmapFromData(disp, temp_win,
mark8_bits, mark_w, mark_h);
XDestroyWindow(disp, temp_win);
}
/*ARGSUSED*/
void
init_X(user_state)
char *user_state;
/*
* Initializes for an X drawing sequence. Sets up drawing attributes
* by reading values from the parameter database.
*/
{
static int initialized = 0;
if (!initialized) {
init_once();
initialized = 1;
}
}
static GC
textGC(t_win, t_font)
Window t_win; /* Window for making GC */
XFontStruct *t_font; /* Text font */
/*
* Sets the fields above in a global graphics context. If
* the graphics context does not exist, it is created.
*/
{
static GC text_gc = (GC) 0;
XGCValues gcvals;
unsigned long gcmask;
gcvals.font = t_font->fid;
gcmask = GCFont;
if (text_gc == (GC) 0) {
gcvals.foreground = PM_PIXEL("Foreground");
gcmask |= GCForeground;
text_gc = XCreateGC(disp, t_win, gcmask, &gcvals);
}
else {
XChangeGC(disp, text_gc, gcmask, &gcvals);
}
return text_gc;
}
static GC
segGC(l_win, l_fg, l_style, l_width, l_chars, l_len)
Window l_win; /* Window for making GC */
Pixel l_fg; /* Foreground color */
int l_style; /* Line style */
int l_width; /* Line width */
char *l_chars; /* Character spec */
int l_len; /* Length of spec */
/*
* Sets the fields above in a global graphics context. If the
* graphics context does not exist, it is created.
*/
{
static GC segment_gc = (GC) 0;
XGCValues gcvals;
unsigned long gcmask;
gcvals.foreground = l_fg;
gcvals.line_style = l_style;
gcvals.line_width = l_width;
gcmask = GCForeground | GCLineStyle | GCLineWidth;
if (segment_gc == (GC) 0) {
segment_gc = XCreateGC(disp, l_win, gcmask, &gcvals);
}
else {
XChangeGC(disp, segment_gc, gcmask, &gcvals);
}
if (l_len > 0) {
XSetDashes(disp, segment_gc, 0, l_chars, l_len);
}
return segment_gc;
}
static GC
dotGC(d_win, d_fg, d_clipmask, d_xorg, d_yorg)
Window d_win; /* Window for making GC */
Pixel d_fg; /* Foreground color */
Pixmap d_clipmask; /* Clipmask */
int d_xorg,
d_yorg; /* Clipmask origin */
/*
* Sets the fields above in a global graphics context. If the
* graphics context does not exist, it is created.
*/
{
static GC dot_gc = (GC) 0;
XGCValues gcvals;
unsigned long gcmask;
gcvals.foreground = d_fg;
gcvals.clip_mask = d_clipmask;
gcvals.clip_x_origin = d_xorg;
gcvals.clip_y_origin = d_yorg;
gcmask = GCForeground | GCClipMask | GCClipXOrigin | GCClipYOrigin;
if (dot_gc == (GC) 0) {
dot_gc = XCreateGC(disp, d_win, gcmask, &gcvals);
}
else {
XChangeGC(disp, dot_gc, gcmask, &gcvals);
}
return dot_gc;
}
void
text_X(user_state, x, y, text, just, style)
char *user_state; /* Value set in xg_init */
int x,
y; /* Text position (pixels) */
char *text; /* Null terminated text */
int just; /* Justification (above) */
int style; /* Text style (above) */
/*
* This routine should draw text at the indicated position using
* the indicated justification and style. The justification refers
* to the location of the point in reference to the text. For example,
* if just is T_LOWERLEFT, (x,y) should be located at the lower left
* edge of the text string.
*/
{
struct x_state *st = (struct x_state *) user_state;
XCharStruct bb;
int rx = 0,
ry = 0,
len,
height,
width,
dir;
int ascent,
descent;
XFontStruct *font;
len = strlen(text);
font = ((style == T_TITLE) ? PM_FONT("TitleFont") : PM_FONT("LabelFont"));
XTextExtents(font, text, len, &dir, &ascent, &descent, &bb);
width = bb.rbearing - bb.lbearing;
height = bb.ascent + bb.descent;
switch (just) {
case T_CENTER:
rx = x - (width / 2);
ry = y - (height / 2);
break;
case T_LEFT:
rx = x;
ry = y - (height / 2);
break;
case T_UPPERLEFT:
rx = x;
ry = y;
break;
case T_TOP:
rx = x - (width / 2);
ry = y;
break;
case T_UPPERRIGHT:
rx = x - width;
ry = y;
break;
case T_RIGHT:
rx = x - width;
ry = y - (height / 2);
break;
case T_LOWERRIGHT:
rx = x - width;
ry = y - height;
break;
case T_BOTTOM:
rx = x - (width / 2);
ry = y - height;
break;
case T_LOWERLEFT:
rx = x;
ry = y - height;
break;
}
XDrawString(disp, st->win,
textGC(st->win, font),
rx, ry + bb.ascent, text, len);
}
void
seg_X(user_state, ns, segs, width, style, lappr, color)
char *user_state; /* Value set in xg_init */
int ns; /* Number of segments */
XSegment *segs; /* X array of segments */
int width; /* Width of lines */
int style; /* See above */
int lappr; /* Line appearence */
int color; /* Line color (if any) */
/*
* This routine draws a number of line segments at the points
* given in `seglist'. Note that contiguous segments need not share
* endpoints but often do. All segments should be `width' devcoords wide
* and drawn in style `style'. If `style' is L_VAR, the parameters
* `color' and `lappr' should be used to draw the line. Both
* parameters vary from 0 to 7. If the device is capable of
* color, `color' varies faster than `style'. If the device
* has no color, `style' will vary faster than `color' and
* `color' can be safely ignored. However, if the
* the device has more than 8 line appearences, the two can
* be combined to specify 64 line style variations.
* Xgraph promises not to send more than the `max_segs' in the
* xgOut structure passed back from xg_init().
*/
{
struct x_state *st = (struct x_state *) user_state;
param_style ps;
GC gc;
if (style == L_AXIS) {
ps = PM_STYLE("GridStyle");
if (ps.len < 2) {
gc = segGC(st->win, PM_PIXEL("Foreground"),
LineSolid, PM_INT("GridSize"), (char *) 0, 0);
}
else {
gc = segGC(st->win, PM_PIXEL("Foreground"),
LineOnOffDash, PM_INT("GridSize"),
ps.dash_list, ps.len);
}
}
else if (style == L_ZERO) {
/* Set the color and line style */
ps = PM_STYLE("ZeroStyle");
if (ps.len < 2) {
gc = segGC(st->win, PM_PIXEL("ZeroColor"),
LineSolid, PM_INT("ZeroWidth"), (char *) 0, 0);
}
else {
gc = segGC(st->win, PM_PIXEL("ZeroColor"),
LineOnOffDash, PM_INT("ZeroWidth"),
ps.dash_list, ps.len);
}
}
else {
/* Color and line style vary */
if (lappr == 0) {
gc = segGC(st->win, AllAttrs[color].pixelValue, LineSolid,
width, (char *) 0, 0);
}
else {
gc = segGC(st->win, AllAttrs[color].pixelValue, LineOnOffDash,
width, AllAttrs[lappr].lineStyle, AllAttrs[lappr].lineStyleLen);
}
/* PW */
if (lappr == 16) {
gc = segGC(st->win, PM_PIXEL("BackGround"), LineSolid,
width, (char *) 0, 0);
}
}
XDrawSegments(disp, st->win, gc, segs, ns);
}
#define LAST_CHECK
void
dot_X(user_state, x, y, style, type, color)
char *user_state; /* Value set in xg_init */
int x,
y; /* Location in pixel units */
int style; /* Dot style */
int type; /* Type of marker */
int color; /* Marker color (if any) */
/*
* This routine should draw a marker at location `x,y'. If the
* style is P_PIXEL, the dot should be a single pixel. If
* the style is P_DOT, the dot should be a reasonably large
* dot. If the style is P_MARK, it should be a distinguished
* mark which is specified by `type' (0-7). If the output
* device is capable of color, the marker should be drawn in
* `color' (0-7) which corresponds with the color for xg_line.
*/
{
struct x_state *st = (struct x_state *) user_state;
switch (style) {
case P_PIXEL:
XDrawPoint(disp, st->win,
dotGC(st->win, AllAttrs[color].pixelValue, (Pixmap) 0, 0, 0),
x, y);
break;
case P_DOT:
XFillRectangle(disp, st->win,
dotGC(st->win, AllAttrs[color].pixelValue, dotMap,
(int) (x - (dot_w >> 1)),
(int) (y - (dot_h >> 1))),
(int) (x - (dot_w >> 1)), (int) (y - (dot_h >> 1)),
dot_w, dot_h);
break;
case P_MARK:
XFillRectangle(disp, st->win,
dotGC(st->win, AllAttrs[color].pixelValue,
AllAttrs[type].markStyle,
(int) (x - mark_cx),
(int) (y - mark_cy)),
(int) (x - mark_cx), (int) (y - mark_cy),
mark_w, mark_h);
break;
}
}