/*
* $Id: hlevel.c,v 1.1.1.1 2005/09/18 22:04:25 dhmunro Exp $
* Define routines for recommended GIST interactive interface
*/
/* Copyright (c) 2005, The Regents of the University of California.
* All rights reserved.
* This file is part of yorick (http://yorick.sourceforge.net).
* Read the accompanying LICENSE file for details.
*/
#include "hlevel.h"
#include "pstdlib.h"
#ifndef NO_XLIB
#ifndef ANIMATE_H
#include "xbasic.h"
#else
#include ANIMATE_H
#endif
#else
#include "engine.h"
static int GxAnimate(Engine *engine, GpBox *viewport);
static int GxStrobe(Engine *engine, int clear);
static int GxDirect(Engine *engine);
static int GxAnimate(Engine *engine, GpBox *viewport)
{ return 0; }
static int GxStrobe(Engine *engine, int clear)
{ return 0; }
static int GxDirect(Engine *engine)
{ return 0; }
#endif
static void UpdateOrRedraw(int changesOnly);
/* Here is a kludge to detect when GdDraw is about to be called to
walk a Drauing. The how argument has these meanings:
even: called just before GdDraw
odd: called after following flush (or other related actions)
0/1: called from UpdateOrRedraw (just before prompt)
2/3: called from GhFMA (explicit frame advance)
4/5: called from GhHCP (with hardcopy Engine, not display engine)
*/
extern void (*gdraw_hook)(Engine *display, int how);
void (*gdraw_hook)(Engine *display, int how)= 0;
/* ------------------------------------------------------------------------ */
/* See README for description of these control functions */
GhDevice ghDevices[GH_NDEVS];
Engine *hcpDefault= 0;
static int currentDevice= -1;
static int hcpOn= 0;
static int animateOn= 0;
static int fmaCount= 0;
static void UpdateOrRedraw(int changesOnly)
{
Engine *display= currentDevice<0? 0 : ghDevices[currentDevice].display;
if (!display) return;
GpPreempt(display);
if (gdraw_hook) gdraw_hook(display, 0);
GdDraw(changesOnly);
GpFlush(0);
if (gdraw_hook) gdraw_hook(display, 1);
GpPreempt(0);
}
void (*g_on_idle)(void) = 0;
void GhBeforeWait(void)
{
#ifndef NO_XLIB
extern void (*g_pending_task)(void); /* auto disconnect, see xbasic.c */
if (g_on_idle) g_on_idle();
if (g_pending_task) g_pending_task();
#else
if (g_on_idle) g_on_idle();
#endif
if (currentDevice<0 || !ghDevices[currentDevice].display ||
animateOn) return; /* nothing happens in animate mode until
* explicit call to GhFMA */
UpdateOrRedraw(1);
}
void GhFMA(void)
{
Engine *display;
Engine *hcp= 0;
if (currentDevice<0) return;
display= ghDevices[currentDevice].display;
if (animateOn && !display) animateOn= 0;
if (hcpOn) {
hcp= ghDevices[currentDevice].hcp;
if (!hcp) hcp= hcpDefault;
if (hcp) GpActivate(hcp);
}
if (gdraw_hook) gdraw_hook(display, 2);
GdDraw(1);
if (hcpOn && hcp && ghDevices[currentDevice].doLegends)
GdDrawLegends(hcp);
if (animateOn) GxStrobe(display, 1);
GpFlush(0);
if (animateOn!=1) GdClear(0);
else GdClearSystem();
if (gdraw_hook) gdraw_hook(display, 3);
if (hcpOn && hcp) {
GpClear(hcp, CONDITIONALLY);
GpDeactivate(hcp);
}
ghDevices[currentDevice].fmaCount++;
if (++fmaCount > 100) { /* clean house once in a while */
fmaCount= 0;
GaFreeScratch();
}
}
void GhRedraw(void)
{
UpdateOrRedraw(-1);
}
void GhHCP(void)
{
Engine *hcp= currentDevice<0? 0 : ghDevices[currentDevice].hcp;
if (!hcp) hcp= hcpDefault;
if (!hcp) return;
GpPreempt(hcp);
if (gdraw_hook) gdraw_hook(hcp, 4);
GdDraw(0);
/* NB- must be very careful not to Preempt twice with GdDrawLegends */
if (ghDevices[currentDevice].doLegends) GdDrawLegends(0);
GpClear(0, ALWAYS);
GpFlush(0);
if (gdraw_hook) gdraw_hook(hcp, 5);
GpPreempt(0);
}
void GhFMAMode(int hcp, int animate)
{
/* 0 off, 1 on, 2 no change, 3 toggle */
if (hcp&2) hcpOn^= (hcp&1); /* if 2 bit, XOR operation */
else hcpOn= (hcp&1); /* else, COPY operation */
if ((animate&3)!=2) {
Engine *display= currentDevice<0? 0 : ghDevices[currentDevice].display;
if (!display) return;
if ((animate&2) || (!animateOn)!=(!(animate&1))) {
/* animation mode will actually change */
animateOn= !animateOn;
if (animateOn) {
GpBox aport;
GpBox *port= GdClearSystem();
/* Can only animate using GdClearSystem if there is a current
system; GdClearSystem returns appropriate box to animate,
or 0 if can't.
If no current system, then animate entire picture using
ordinary GpClear. */
aport.xmin= 0.0;
aport.xmax= 2.0;
aport.ymin= 0.0;
aport.ymax= 2.0;
/* if (!port) { just animate everything */
port= &aport;
animateOn= 2;
/* } */
if (GxAnimate(display, port)) animateOn= 0;
} else {
GxDirect(display);
}
}
}
}
int GhSetPlotter(int number)
{
if (number<0 || number>=GH_NDEVS) return 1;
if (currentDevice>=0) {
if (ghDevices[currentDevice].display) {
GdSetDrawing(ghDevices[currentDevice].drawing);
GhBeforeWait();
GpDeactivate(ghDevices[currentDevice].display);
}
if (ghDevices[currentDevice].hcp)
GpDeactivate(ghDevices[currentDevice].hcp);
}
if (hcpDefault) GpDeactivate(hcpDefault);
currentDevice= number;
if (ghDevices[number].display) GpActivate(ghDevices[number].display);
return GdSetDrawing(ghDevices[number].drawing);
}
int GhGetPlotter(void)
{
return currentDevice;
}
#ifndef NO_XLIB
/* xbasic.c supplies a hook in its error handlers to allow the hlevel
to clear its display devices */
static void ShutDownDev(Engine *engine);
extern void (*HLevelHook)(Engine *engine);
static void ShutDownDev(Engine *engine)
{
int i;
if (hcpDefault==engine) hcpDefault= 0;
for (i=0 ; i<GH_NDEVS ; i++) {
if (ghDevices[i].display==engine) {
if (i==currentDevice) currentDevice= -1;
ghDevices[i].display= 0;
}
if (ghDevices[i].hcp==engine) {
if (!ghDevices[i].display && i==currentDevice) currentDevice= -1;
ghDevices[i].hcp= 0;
}
}
}
int GhSetXHandler(void (*ErrHandler)(char *errMsg))
{
GpSetXHandler(ErrHandler);
HLevelHook= &ShutDownDev;
return 0;
}
#else
/* ARGSUSED */
int GhSetXHandler(void (*ErrHandler)(char *errMsg))
{
/* no-op */
return 0;
}
#endif
/* ------------------------------------------------------------------------ */
/* Default management */
static GpLineAttribs lDefault= { FG_COLOR, L_SOLID, 1.0 };
static GpMarkerAttribs mDefault= { FG_COLOR, 0, 1.0 };
static GpFillAttribs fDefault= { FG_COLOR, F_SOLID };
static GpTextAttribs tDefault= { FG_COLOR, 0, 0.0156,
TX_RIGHT, TH_NORMAL, TV_NORMAL };
static GaLineAttribs dlDefault= { 0, 0, 0, 0.16, 0.14, 0,
0.13, 0.11375, 1.0, 1.0 };
static GaVectAttribs vectDefault= { 0, 0.125 };
static GpLineAttribs edgeDefault= { FG_COLOR, L_NONE, 1.0 };
void GhGetLines(void)
{
gistA.l= lDefault;
gistA.m= mDefault;
gistA.dl= dlDefault;
}
void GhGetText(void)
{
gistA.t= tDefault;
}
void GhGetMesh(void)
{
gistA.l= lDefault;
}
void GhGetVectors(void)
{
gistA.l= lDefault;
gistA.f= fDefault;
gistA.vect= vectDefault;
}
void GhGetFill(void)
{
gistA.e= edgeDefault;
}
void GhSetLines(void)
{
lDefault= gistA.l;
mDefault= gistA.m;
mDefault.type= 0; /* never a default marker */
dlDefault= gistA.dl;
}
void GhSetText(void)
{
tDefault= gistA.t;
}
void GhSetMesh(void)
{
lDefault= gistA.l;
}
void GhSetVectors(void)
{
lDefault= gistA.l;
fDefault= gistA.f;
vectDefault= gistA.vect;
}
void GhSetFill(void)
{
edgeDefault= gistA.e;
}
/* ------------------------------------------------------------------------ */
void GhDumpColors(int n, int hcp, int pryvate)
{
Engine *engine;
if (n>=0 && n<GH_NDEVS) {
if (hcp) engine= ghDevices[n].hcp;
else engine= ghDevices[n].display;
} else {
engine= hcpDefault;
}
if (engine) GpDumpColors(engine, pryvate);
}
int GhGetColorMode(Engine *engine)
{
return engine->colorMode;
}
void GhSetPalette(int n, GpColorCell *palette, int nColors)
{
if (n==-1) n = currentDevice;
if (n<0 || n>=GH_NDEVS) return;
if (ghDevices[n].display && ghDevices[n].display->palette!=palette) {
GpSetPalette(ghDevices[n].display, palette, nColors);
if (!ghDevices[n].display->colorMode) GhRedraw();
}
if (ghDevices[n].hcp && ghDevices[n].hcp->palette!=palette)
GpSetPalette(ghDevices[n].hcp, palette, nColors);
}
int GhReadPalette(int n, const char *gpFile,
GpColorCell **palette, int maxColors)
{
int paletteSize= 0;
if (n==-1) n = currentDevice;
else if (n<0 || n>=GH_NDEVS) return 0;
if (ghDevices[n].display) {
paletteSize= GpReadPalette(ghDevices[n].display, gpFile,
&ghDevices[n].display->palette, maxColors);
if (ghDevices[n].hcp)
GpSetPalette(ghDevices[n].hcp,
ghDevices[n].display->palette,
ghDevices[n].display->nColors);
if (palette) *palette= ghDevices[n].display->palette;
/* override the (possibly truncated) value returned by GpReadPalette */
paletteSize= ghDevices[n].display->nColors;
if (!ghDevices[n].display->colorMode) GhRedraw();
} else if (ghDevices[n].hcp) {
paletteSize= GpReadPalette(ghDevices[n].hcp, gpFile,
&ghDevices[n].hcp->palette, maxColors);
if (palette) *palette= ghDevices[n].hcp->palette;
/* override the (possibly truncated) value returned by GpReadPalette */
paletteSize= ghDevices[n].hcp->nColors;
}
return paletteSize;
}
int GhGetPalette(int n, GpColorCell **palette)
{
*palette= 0;
if (n==-1) n = currentDevice;
if (n<0 || n>=GH_NDEVS) return 0;
if (ghDevices[n].display)
return GpGetPalette(ghDevices[n].display, palette);
else if (ghDevices[n].hcp)
return GpGetPalette(ghDevices[n].hcp, palette);
else
return 0;
}
void GhDeletePalette(int n)
{
GpColorCell *palette= 0;
if (n<0 || n>=GH_NDEVS) return;
if (ghDevices[n].display) palette= ghDevices[n].display->palette;
else if (ghDevices[n].hcp) palette= ghDevices[n].hcp->palette;
if (palette) {
int i;
/* clear palette for this device */
if (ghDevices[n].display)
GpSetPalette(ghDevices[n].display, (GpColorCell *)0, 0);
if (ghDevices[n].hcp)
GpSetPalette(ghDevices[n].hcp, (GpColorCell *)0, 0);
/* free the palette if there are no other references to it */
for (i=0 ; i<GH_NDEVS ; i++)
if ((ghDevices[i].display &&
ghDevices[i].display->palette==palette) ||
(ghDevices[i].hcp &&
ghDevices[i].hcp->palette==palette)) break;
if (i>=GH_NDEVS) {
if (hcpDefault && palette==hcpDefault->palette)
GpSetPalette(hcpDefault, (GpColorCell *)0, 0);
p_free(palette);
}
}
}
void SetHCPPalette(void)
{
if (hcpDefault && currentDevice>=0) {
GpColorCell *palette= 0;
int nColors= 0;
if (ghDevices[currentDevice].display) {
palette= ghDevices[currentDevice].display->palette;
nColors= ghDevices[currentDevice].display->nColors;
} else if (ghDevices[currentDevice].hcp) {
palette= ghDevices[currentDevice].hcp->palette;
nColors= ghDevices[currentDevice].hcp->nColors;
}
GpSetPalette(hcpDefault, palette, nColors);
}
}
/* ------------------------------------------------------------------------ */
syntax highlighted by Code2HTML, v. 0.9.1