#include <cdk_int.h>
/*
* $Author: tom $
* $Date: 2004/08/30 00:18:12 $
* $Revision: 1.78 $
*/
DeclareCDKObjects(GRAPH, Graph, setCdk, Unknown);
#define TITLE_LM 3
/*
* This creates a graph widget.
*/
CDKGRAPH *newCDKGraph (CDKSCREEN *cdkscreen, int xplace, int yplace, int height, int width, char *title, char *xtitle, char *ytitle)
{
CDKGRAPH *graph = 0;
int parentWidth = getmaxx(cdkscreen->window);
int parentHeight = getmaxy(cdkscreen->window);
int boxWidth = width;
int boxHeight = height;
int xpos = xplace;
int ypos = yplace;
if ((graph = newCDKObject(CDKGRAPH, &my_funcs)) == 0)
return (0);
setCDKGraphBox (graph, FALSE);
/*
* If the height is a negative value, the height will
* be ROWS-height, otherwise, the height will be the
* given height.
*/
boxHeight = setWidgetDimension (parentHeight, height, 3);
/*
* If the width is a negative value, the width will
* be COLS-width, otherwise, the width will be the
* given width.
*/
boxWidth = setWidgetDimension (parentWidth, width, 0);
/*
* If the width is a negative value, the width will
* be COLS-width, otherwise, the width will be the
* given width.
*/
boxWidth = setWidgetDimension (parentWidth, width, 0);
boxWidth = setCdkTitle(ObjOf(graph), title, boxWidth);
boxHeight += TitleLinesOf(graph);
/*
* Make sure we didn't extend beyond the dimensions of the window.
*/
boxWidth = (boxWidth > parentWidth ? parentWidth : boxWidth);
boxHeight = (boxHeight > parentHeight ? parentHeight : boxHeight);
/* Rejustify the x and y positions if we need to. */
alignxy (cdkscreen->window, &xpos, &ypos, boxWidth, boxHeight);
/* Create the graph pointer. */
ScreenOf(graph) = cdkscreen;
graph->parent = cdkscreen->window;
graph->win = newwin (boxHeight, boxWidth, ypos, xpos);
graph->boxHeight = boxHeight;
graph->boxWidth = boxWidth;
graph->minx = 0;
graph->maxx = 0;
graph->xscale = 0;
graph->yscale = 0;
graph->count = 0;
graph->displayType = vLINE;
/* Is the graph pointer null? */
if (graph->win == 0)
{
destroyCDKObject(graph);
return ( 0 );
}
keypad (graph->win, TRUE);
/* Translate the X Axis title char * to a chtype * */
if (xtitle != 0)
{
graph->xtitle = char2Chtype (xtitle, &graph->xtitleLen, &graph->xtitlePos);
graph->xtitlePos = justifyString (graph->boxHeight, graph->xtitleLen, graph->xtitlePos);
}
else
{
graph->xtitle = char2Chtype ("<C></5>X Axis", &graph->xtitleLen, &graph->xtitlePos);
graph->xtitlePos = justifyString (graph->boxHeight, graph->xtitleLen, graph->xtitlePos);
}
/* Translate the Y Axis title char * to a chtype * */
if (ytitle != 0)
{
graph->ytitle = char2Chtype (ytitle, &graph->ytitleLen, &graph->ytitlePos);
graph->ytitlePos = justifyString (graph->boxWidth, graph->ytitleLen, graph->ytitlePos);
}
else
{
graph->ytitle = char2Chtype ("<C></5>Y Axis", &graph->ytitleLen, &graph->ytitlePos);
graph->ytitlePos = justifyString (graph->boxWidth, graph->ytitleLen, graph->ytitlePos);
}
/* Set some values of the graph structure. */
graph->graphChar = 0;
/* Register this baby. */
registerCDKObject (cdkscreen, vGRAPH, graph);
/* Return the graph pointer. */
return (graph);
}
/*
* This was added for the builder.
*/
void activateCDKGraph (CDKGRAPH *graph, chtype *actions GCC_UNUSED)
{
drawCDKGraph (graph, ObjOf(graph)->box);
}
/*
* This sets multiple attributes of the widget.
*/
int setCDKGraph (CDKGRAPH *graph, int *values, int count, char *graphChar, boolean startAtZero, EGraphDisplayType displayType)
{
int ret;
ret = setCDKGraphValues (graph, values, count, startAtZero);
setCDKGraphCharacters (graph, graphChar);
setCDKGraphDisplayType (graph, displayType);
return ret;
}
/*
* Set the scale factors for the graph after we have loaded new values.
*/
static void setScales (CDKGRAPH *graph)
{
graph->xscale = ((graph->maxx - graph->minx) / MAXIMUM(1, (graph->boxHeight - TitleLinesOf(graph) - 5)));
if (graph->xscale <= 0)
graph->xscale = 1;
graph->yscale = ((graph->boxWidth-4) / MAXIMUM(1, graph->count));
if (graph->yscale <= 0)
graph->yscale = 1;
}
/*
* This sets the values of the graph.
*/
int setCDKGraphValues (CDKGRAPH *graph, int *values, int count, boolean startAtZero)
{
int min = INT_MAX;
int max = INT_MIN;
int x;
/* Make sure everything is happy. */
if (count < 0)
return (FALSE);
if (graph->values != 0)
{
free (graph->values);
graph->values = 0;
graph->count = 0;
}
if ((graph->values = typeCallocN(int, count + 1)) == 0)
return FALSE;
/* Copy the X values. */
for (x=0; x < count; x++)
{
/* Determine the min/max values of the graph. */
min = MINIMUM (values[x], graph->minx);
max = MAXIMUM (values[x], graph->maxx);
/* Copy the value. */
graph->values[x] = values[x];
}
/* Keep the count and min/max values. */
graph->count = count;
graph->minx = min;
graph->maxx = max;
/* Check the start at zero status. */
if (startAtZero)
{
graph->minx = 0;
}
setScales (graph);
return (TRUE);
}
int *getCDKGraphValues (CDKGRAPH *graph, int *size)
{
(*size) = graph->count;
return graph->values;
}
/*
* This sets the value of the graph at the given index.
*/
int setCDKGraphValue (CDKGRAPH *graph, int Index, int value, boolean startAtZero)
{
/* Make sure the index is within range. */
if (Index < 0 || Index >= graph->count)
{
return (FALSE);
}
/* Set the min, max, and value for the graph. */
graph->minx = MINIMUM (value, graph->minx);
graph->maxx = MAXIMUM (value, graph->maxx);
graph->values[Index] = value;
/* Check the start at zero status. */
if (startAtZero)
{
graph->minx = 0;
}
setScales (graph);
return (TRUE);
}
int getCDKGraphValue (CDKGRAPH *graph, int Index)
{
return Index >= 0 && Index < graph->count ? graph->values[Index] : 0;
}
/*
* This sets the characters of the graph widget.
*/
int setCDKGraphCharacters (CDKGRAPH *graph, char *characters)
{
chtype *newTokens = 0;
int charCount, junk;
/* Convert the string given to us. */
newTokens = char2Chtype (characters, &charCount, &junk);
/*
* Check if the number of characters back is the same as the number
* of elements in the list.
*/
if (charCount != graph->count)
{
freeChtype (newTokens);
return (FALSE);
}
/* Evrything OK so far. Nuke the old pointer and use the new one. */
freeChtype (graph->graphChar);
graph->graphChar = newTokens;
return (TRUE);
}
chtype *getCDKGraphCharacters (CDKGRAPH *graph)
{
return graph->graphChar;
}
/*
* This sets the character of the graph widget of the given index.
*/
int setCDKGraphCharacter (CDKGRAPH *graph, int Index, char *character)
{
chtype *newTokens = 0;
int charCount, junk;
/* Make sure the index is within range. */
if (Index < 0 || Index > graph->count)
{
return (FALSE);
}
/* Convert the string given to us. */
newTokens = char2Chtype (character, &charCount, &junk);
/*
* Check if the number of characters back is the same as the number
* of elements in the list.
*/
if (charCount != graph->count)
{
freeChtype (newTokens);
return (FALSE);
}
/* Evrything OK so far. Set the value of the array. */
graph->graphChar[Index] = newTokens[0];
freeChtype (newTokens);
return (TRUE);
}
chtype getCDKGraphCharacter (CDKGRAPH *graph, int Index)
{
return graph->graphChar[Index];
}
/*
* This sets the display type of the graph.
*/
void setCDKGraphDisplayType (CDKGRAPH *graph, EGraphDisplayType type)
{
graph->displayType = type;
}
EGraphDisplayType getCDKGraphDisplayType (CDKGRAPH *graph)
{
return graph->displayType;
}
/*
* This sets the background attribute of the widget.
*/
static void _setBKattrGraph (CDKOBJS *object, chtype attrib)
{
if (object != 0)
{
CDKGRAPH *widget = (CDKGRAPH *)object;
wbkgd (widget->win, attrib);
}
}
/*
* This moves the graph field to the given location.
*/
static void _moveCDKGraph (CDKOBJS *object, int xplace, int yplace, boolean relative, boolean refresh_flag)
{
CDKGRAPH *graph = (CDKGRAPH *)object;
int currentX = getbegx(graph->win);
int currentY = getbegy(graph->win);
int xpos = xplace;
int ypos = yplace;
int xdiff = 0;
int ydiff = 0;
/*
* If this is a relative move, then we will adjust where we want
* to move to.
*/
if (relative)
{
xpos = getbegx(graph->win) + xplace;
ypos = getbegy(graph->win) + yplace;
}
/* Adjust the window if we need to. */
alignxy (WindowOf(graph), &xpos, &ypos, graph->boxWidth, graph->boxHeight);
/* Get the difference. */
xdiff = currentX - xpos;
ydiff = currentY - ypos;
/* Move the window to the new location. */
moveCursesWindow(graph->win, -xdiff, -ydiff);
moveCursesWindow(graph->shadowWin, -xdiff, -ydiff);
/* Touch the windows so they 'move'. */
refreshCDKWindow (WindowOf(graph));
/* Redraw the window, if they asked for it. */
if (refresh_flag)
{
drawCDKGraph (graph, ObjOf(graph)->box);
}
}
/*
* This sets whether or not the graph will be boxed.
*/
void setCDKGraphBox (CDKGRAPH *graph, boolean Box)
{
ObjOf(graph)->box = Box;
ObjOf(graph)->borderSize = Box ? 1 : 0;
}
boolean getCDKGraphBox (CDKGRAPH *graph)
{
return ObjOf(graph)->box;
}
/*
* This function draws the graph widget.
*/
static void _drawCDKGraph (CDKOBJS *object, boolean Box)
{
CDKGRAPH *graph = (CDKGRAPH *)object;
int adj = 2 + (graph->xtitle == 0 ? 0 : 1);
int spacing = 0;
chtype attrib = ' '|A_REVERSE;
char temp[100];
int x, y, xpos, ypos, len;
/* Box it if needed. */
if (Box)
{
drawObjBox (graph->win, ObjOf(graph));
}
/* Draw in the vertical axis. */
drawLine (graph->win, 2, TitleLinesOf(graph) + 1, 2, graph->boxHeight-3, ACS_VLINE);
/* Draw in the horizontal axis. */
drawLine (graph->win, 3, graph->boxHeight-3, graph->boxWidth, graph->boxHeight-3, ACS_HLINE);
drawCdkTitle (graph->win, object);
/* Draw in the X axis title. */
if (graph->xtitle != 0)
{
writeChtype (graph->win, 0, graph->xtitlePos, graph->xtitle, VERTICAL, 0, graph->xtitleLen);
attrib = graph->xtitle[0] & A_ATTRIBUTES;
}
/* Draw in the X axis high value. */
sprintf (temp, "%d", graph->maxx);
len = (int)strlen (temp);
writeCharAttrib (graph->win, 1, TitleLinesOf(graph) + 1, temp, attrib, VERTICAL, 0, len);
/* Draw in the X axis low value. */
sprintf (temp, "%d", graph->minx);
len = (int)strlen (temp);
writeCharAttrib (graph->win, 1, graph->boxHeight-2-len, temp, attrib, VERTICAL, 0, len);
/* Draw in the Y axis title. */
if (graph->ytitle != 0)
{
writeChtype (graph->win, graph->ytitlePos, graph->boxHeight-1, graph->ytitle, HORIZONTAL, 0, graph->ytitleLen);
attrib = graph->ytitle[0] & A_ATTRIBUTES;
}
/* Draw in the Y axis high value. */
sprintf (temp, "%d", graph->count);
len = (int)strlen (temp);
writeCharAttrib (graph->win, graph->boxWidth-len-adj, graph->boxHeight-2, temp, attrib, HORIZONTAL, 0, len);
/* Draw in the Y axis low value. */
sprintf (temp, "0");
writeCharAttrib (graph->win, 3, graph->boxHeight-2, temp, attrib, HORIZONTAL, 0, (int)strlen(temp));
/* If the count is zero, then there aren't any points. */
if (graph->count == 0)
{
wrefresh (graph->win);
return;
}
spacing = (graph->boxWidth - TITLE_LM) / graph->count;
/* Draw in the graph line/plot points. */
for (y=0; y < graph->count; y++)
{
int colheight = (graph->values[y] / graph->xscale) - 1;
/* Add the marker on the Y axis. */
mvwaddch (graph->win, graph->boxHeight-3, (y + 1)*spacing + adj, ACS_TTEE);
/* If this is a plot graph, all we do is draw a dot. */
if (graph->displayType == vPLOT)
{
xpos = graph->boxHeight-4-colheight;
ypos = (y + 1)*spacing + adj;
mvwaddch (graph->win, xpos, ypos, graph->graphChar[y]);
}
else
{
for (x=0; x <= graph->yscale; x++)
{
xpos = graph->boxHeight-3;
ypos = (y + 1)*spacing + adj;
drawLine (graph->win, ypos, xpos-colheight, ypos, xpos, graph->graphChar[y]);
}
}
}
/* Draw in the axis corners. */
mvwaddch (graph->win, TitleLinesOf(graph), 2, ACS_URCORNER);
mvwaddch (graph->win, graph->boxHeight-3, 2, ACS_LLCORNER);
mvwaddch (graph->win, graph->boxHeight-3, graph->boxWidth, ACS_URCORNER);
/* Refresh and lets see 'er. */
refreshCDKWindow (graph->win);
}
/*
* This function destroys the graph widget.
*/
static void _destroyCDKGraph (CDKOBJS *object)
{
if (object != 0)
{
CDKGRAPH *graph = (CDKGRAPH *)object;
cleanCdkTitle (object);
freeChtype (graph->xtitle);
freeChtype (graph->ytitle);
freeChtype (graph->graphChar);
freeChecked (graph->values);
/* Unregister this object. */
unregisterCDKObject (vGRAPH, graph);
/* Clean up the windows. */
deleteCursesWindow (graph->win);
}
}
/*
* This function erases the graph widget from the screen.
*/
static void _eraseCDKGraph (CDKOBJS *object)
{
if (validCDKObject (object))
{
CDKGRAPH *graph = (CDKGRAPH *)object;
eraseCursesWindow (graph->win);
}
}
dummyInject(Graph)
dummyFocus(Graph)
dummyUnfocus(Graph)
dummyRefreshData(Graph)
dummySaveData(Graph)
syntax highlighted by Code2HTML, v. 0.9.1