Improve deriving from Fl_Chart (STR 2022)

This commit makes the local, static drawing functions in the source
file available for subclasses by converting them to static protected
methods as requested by STR 2022.

The source and header files have been reformatted according to the
CMP, documentation for the new protected methods was added.

Source code *functionality* has not been changed.

This resolves and closes STR 2022.

Todo:
 - investigate whether these drawing methods wouldn't better be
   member functions and "convert" them if applicable
 - investigate whether the internal struct FL_CHART_ENTRY could become
   a local part of the Fl_Chart class, maybe Fl_Chart::Entry.
 - rename private member variables with trailing underscore (see CMP)
This commit is contained in:
Albrecht Schlosser 2023-01-15 22:16:50 +01:00
parent 02ca05c6b2
commit dde2d21b5d
2 changed files with 426 additions and 323 deletions

View File

@ -1,7 +1,7 @@
//
// Forms chart header file for the Fast Light Tool Kit (FLTK).
// Fl_Chart widget header file for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2010 by Bill Spitzak and others.
// Copyright 1998-2023 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@ -14,8 +14,9 @@
// https://www.fltk.org/bugs.php
//
/* \file
Fl_Chart widget . */
/** \file FL/Fl_Chart.H
\brief Fl_Chart widget.
*/
#ifndef Fl_Chart_H
#define Fl_Chart_H
@ -25,24 +26,24 @@
#endif
// values for type()
#define FL_BAR_CHART 0 /**< type() for Bar Chart variant */
#define FL_HORBAR_CHART 1 /**< type() for Horizontal Bar Chart variant */
#define FL_LINE_CHART 2 /**< type() for Line Chart variant */
#define FL_FILL_CHART 3 /**< type() for Fill Line Chart variant */
#define FL_SPIKE_CHART 4 /**< type() for Spike Chart variant */
#define FL_PIE_CHART 5 /**< type() for Pie Chart variant */
#define FL_SPECIALPIE_CHART 6 /**< type() for Special Pie Chart variant */
#define FL_BAR_CHART 0 ///< type() for Bar Chart variant
#define FL_HORBAR_CHART 1 ///< type() for Horizontal Bar Chart variant
#define FL_LINE_CHART 2 ///< type() for Line Chart variant
#define FL_FILL_CHART 3 ///< type() for Fill Line Chart variant
#define FL_SPIKE_CHART 4 ///< type() for Spike Chart variant
#define FL_PIE_CHART 5 ///< type() for Pie Chart variant
#define FL_SPECIALPIE_CHART 6 ///< type() for Special Pie Chart variant
#define FL_FILLED_CHART FL_FILL_CHART /**< for compatibility */
#define FL_FILLED_CHART FL_FILL_CHART ///< for compatibility
#define FL_CHART_MAX 128 /**< max entries per chart */
#define FL_CHART_LABEL_MAX 18 /**< max label length for entry */
#define FL_CHART_MAX 128 ///< max entries per chart
#define FL_CHART_LABEL_MAX 18 ///< max label length for entry
/** For internal use only */
/** For internal use only. */
struct FL_CHART_ENTRY {
float val; /**< For internal use only. */
unsigned col; /**< For internal use only. */
char str[FL_CHART_LABEL_MAX+1]; /**< For internal use only. */
float val; ///< For internal use only.
unsigned col; ///< For internal use only.
char str[FL_CHART_LABEL_MAX + 1]; ///< For internal use only.
};
/**
@ -52,94 +53,126 @@ struct FL_CHART_ENTRY {
\image html charts.png
\image latex charts.png "Fl_Chart" width=10cm
\todo Refactor Fl_Chart::type() information.
The type of an Fl_Chart object can be set using type(uchar t) to:
\li \c FL_BAR_CHART: Each sample value is drawn as a vertical bar.
\li \c FL_FILLED_CHART: The chart is filled from the bottom of the graph
to the sample values.
\li \c FL_HORBAR_CHART: Each sample value is drawn as a horizontal bar.
\li \c FL_LINE_CHART: The chart is drawn as a polyline with vertices at
each sample value.
\li \c FL_PIE_CHART: A pie chart is drawn with each sample value being
drawn as a proportionate slice in the circle.
\li \c FL_SPECIALPIE_CHART: Like \c FL_PIE_CHART, but the first slice is
separated from the pie.
\li \c FL_SPIKE_CHART: Each sample value is drawn as a vertical line.
*/
| Chart Type | Description |
|---------------------|-------------------------------------------------------------------------------------------------|
| FL_BAR_CHART | Each sample value is drawn as a vertical bar. |
| FL_FILLED_CHART | The chart is filled from the bottom of the graph to the sample values. |
| FL_HORBAR_CHART | Each sample value is drawn as a horizontal bar. |
| FL_LINE_CHART | The chart is drawn as a polyline with vertices at each sample value. |
| FL_PIE_CHART | A pie chart is drawn with each sample value being drawn as a proportionate slice in the circle. |
| FL_SPECIALPIE_CHART | Like \c FL_PIE_CHART, but the first slice is separated from the pie. |
| FL_SPIKE_CHART | Each sample value is drawn as a vertical line. |
*/
class FL_EXPORT Fl_Chart : public Fl_Widget {
int numb;
int maxnumb;
int sizenumb;
FL_CHART_ENTRY *entries;
double min,max;
uchar autosize_;
Fl_Font textfont_;
Fl_Fontsize textsize_;
Fl_Color textcolor_;
int numb;
int maxnumb;
int sizenumb;
FL_CHART_ENTRY *entries;
double min, max;
uchar autosize_;
Fl_Font textfont_;
Fl_Fontsize textsize_;
Fl_Color textcolor_;
protected:
void draw() FL_OVERRIDE;
void draw() FL_OVERRIDE;
// (static) protected draw methods (STR 2022)
// these methods are documented in src/Fl_Chart.cxx
static void draw_barchart(int x, int y, int w, int h, int numb, FL_CHART_ENTRY entries[],
double min, double max, int autosize, int maxnumb, Fl_Color textcolor);
static void draw_horbarchart(int x, int y, int w, int h, int numb, FL_CHART_ENTRY entries[],
double min, double max, int autosize, int maxnumb,
Fl_Color textcolor);
static void draw_linechart(int type, int x, int y, int w, int h, int numb,
FL_CHART_ENTRY entries[], double min, double max, int autosize,
int maxnumb, Fl_Color textcolor);
static void draw_piechart(int x, int y, int w, int h, int numb, FL_CHART_ENTRY entries[],
int special, Fl_Color textcolor);
public:
Fl_Chart(int X, int Y, int W, int H, const char *L = 0);
Fl_Chart(int X, int Y, int W, int H, const char *L = 0);
~Fl_Chart();
~Fl_Chart();
void clear();
void clear();
void add(double val, const char *str = 0, unsigned col = 0);
void add(double val, const char *str = 0, unsigned col = 0);
void insert(int ind, double val, const char *str = 0, unsigned col = 0);
void insert(int ind, double val, const char *str = 0, unsigned col = 0);
void replace(int ind, double val, const char *str = 0, unsigned col = 0);
void replace(int ind, double val, const char *str = 0, unsigned col = 0);
/**
Gets the lower and upper bounds of the chart values.
\param[out] a, b are set to lower, upper
*/
void bounds(double *a,double *b) const {*a = min; *b = max;}
/**
Gets the lower and upper bounds of the chart values.
\param[out] a, b are set to lower, upper
*/
void bounds(double *a, double *b) const {
*a = min;
*b = max;
}
void bounds(double a,double b);
void bounds(double a, double b);
/**
Returns the number of data values in the chart.
*/
int size() const {return numb;}
/**
Returns the number of data values in the chart.
*/
int size() const { return numb; }
void size(int W, int H) { Fl_Widget::size(W, H); }
/**
Sets the widget size (width, height).
/**
Gets the maximum number of data values for a chart.
*/
int maxsize() const {return maxnumb;}
This is the same as calling Fl_Widget::size(int W, int H);
void maxsize(int m);
\param[in] W,H new width and height of the widget
*/
void size(int W, int H) { Fl_Widget::size(W, H); }
/** Gets the chart's text font */
Fl_Font textfont() const {return textfont_;}
/** Sets the chart's text font to \p s. */
void textfont(Fl_Font s) {textfont_ = s;}
/**
Gets the maximum number of data values for a chart.
*/
int maxsize() const { return maxnumb; }
/** Gets the chart's text size */
Fl_Fontsize textsize() const {return textsize_;}
/** gets the chart's text size to \p s. */
void textsize(Fl_Fontsize s) {textsize_ = s;}
void maxsize(int m);
/** Gets the chart's text color */
Fl_Color textcolor() const {return textcolor_;}
/** gets the chart's text color to \p n. */
void textcolor(Fl_Color n) {textcolor_ = n;}
/** Gets the chart's text font */
Fl_Font textfont() const { return textfont_; }
/**
Get whether the chart will automatically adjust the bounds of the chart.
\returns non-zero if auto-sizing is enabled and zero if disabled.
*/
uchar autosize() const {return autosize_;}
/** Sets the chart's text font to \p s. */
void textfont(Fl_Font s) { textfont_ = s; }
/**
Set whether the chart will automatically adjust the bounds of the chart.
\param[in] n non-zero to enable automatic resizing, zero to disable.
*/
void autosize(uchar n) {autosize_ = n;}
/** Gets the chart's text size */
Fl_Fontsize textsize() const { return textsize_; }
/** Sets the chart's text size to \p s. */
void textsize(Fl_Fontsize s) { textsize_ = s; }
/** Gets the chart's text color */
Fl_Color textcolor() const { return textcolor_; }
/** Sets the chart's text color to \p n. */
void textcolor(Fl_Color n) { textcolor_ = n; }
/**
Gets whether the chart will automatically adjust the bounds of the chart.
\returns non-zero if auto-sizing is enabled and zero if disabled.
*/
uchar autosize() const { return autosize_; }
/**
Sets whether the chart will automatically adjust the bounds of the chart.
\param[in] n non-zero to enable automatic resizing, zero to disable.
*/
void autosize(uchar n) { autosize_ = n; }
};
#endif

View File

@ -1,7 +1,7 @@
//
// Forms-compatible chart widget for the Fast Light Tool Kit (FLTK).
// Chart widget for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2010 by Bill Spitzak and others.
// Copyright 1998-2023 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@ -21,290 +21,347 @@
#include "flstring.h"
#include <stdlib.h>
#define ARCINC (2.0*M_PI/360.0)
// this function is in fl_boxtype.cxx:
void fl_rectbound(int x,int y,int w,int h, Fl_Color color);
void fl_rectbound(int x, int y, int w, int h, Fl_Color color);
/* Widget specific information */
static void draw_barchart(int x,int y,int w,int h,
int numb, FL_CHART_ENTRY entries[],
double min, double max, int autosize, int maxnumb,
Fl_Color textcolor)
/* Draws a bar chart. x,y,w,h is the bounding box, entries the array of
numb entries and min and max the boundaries. */
static const double ARCINC = (2.0 * M_PI / 360.0);
/**
Draws a bar chart.
\p x, \p y, \p w, \p h is the bounding box,
\p entries the array of \p numb entries,
and \p min and \p max the boundaries.
\param[in] x, y, w, h Widget position and size
\param[in] numb Number of values
\param[in] entries Array of values
\param[in] min Lower boundary
\param[in] max Upper boundary
\param[in] autosize Whether the chart autosizes
\param[in] maxnumb Maximal number of entries
\param[in] textcolor Text color
*/
void Fl_Chart::draw_barchart(int x, int y, int w, int h, int numb, FL_CHART_ENTRY entries[],
double min, double max, int autosize, int maxnumb, Fl_Color textcolor)
{
double incr;
int zeroh;
double lh = fl_height();
if (max == min) incr = h;
else incr = h/(max-min);
if ( (-min*incr) < lh) {
incr = (h - lh + min*incr)/(max-min);
zeroh = int(y+h-lh);
if (max == min)
incr = h;
else
incr = h / (max - min);
if ((-min * incr) < lh) {
incr = (h - lh + min * incr) / (max - min);
zeroh = int(y + h - lh);
} else {
zeroh = (int)rint(y+h+min * incr);
zeroh = (int)rint(y + h + min * incr);
}
int bwidth = (int)rint(w/double(autosize?numb:maxnumb));
/* Draw base line */
int bwidth = (int)rint(w / double(autosize ? numb : maxnumb));
// Draw base line
fl_color(textcolor);
fl_line(x, zeroh, x+w, zeroh);
if (min == 0.0 && max == 0.0) return; /* Nothing else to draw */
fl_line(x, zeroh, x + w, zeroh);
if (min == 0.0 && max == 0.0)
return; // Nothing else to draw
int i;
/* Draw the bars */
for (i=0; i<numb; i++) {
int hh = (int)rint(entries[i].val*incr);
if (hh < 0)
fl_rectbound(x+i*bwidth,zeroh,bwidth+1,-hh+1, (Fl_Color)entries[i].col);
else if (hh > 0)
fl_rectbound(x+i*bwidth,zeroh-hh,bwidth+1,hh+1,(Fl_Color)entries[i].col);
// Draw the bars
for (i = 0; i < numb; i++) {
int hh = (int)rint(entries[i].val * incr);
if (hh < 0)
fl_rectbound(x + i * bwidth, zeroh, bwidth + 1, -hh + 1, (Fl_Color)entries[i].col);
else if (hh > 0)
fl_rectbound(x + i * bwidth, zeroh - hh, bwidth + 1, hh + 1, (Fl_Color)entries[i].col);
}
/* Draw the labels */
// Draw the labels
fl_color(textcolor);
for (i=0; i<numb; i++)
fl_draw(entries[i].str,
x+i*bwidth+bwidth/2,zeroh,0,0,
FL_ALIGN_TOP);
for (i = 0; i < numb; i++)
fl_draw(entries[i].str, x + i * bwidth + bwidth / 2, zeroh, 0, 0, FL_ALIGN_TOP);
}
static void draw_horbarchart(int x,int y,int w,int h,
int numb, FL_CHART_ENTRY entries[],
double min, double max, int autosize, int maxnumb,
Fl_Color textcolor)
/* Draws a horizontal bar chart. x,y,w,h is the bounding box, entries the
array of numb entries and min and max the boundaries. */
/**
Draws a horizontal bar chart.
\p x, \p y, \p w, \p h is the bounding box,
\p entries the array of \p numb entries,
and \p min and \p max the boundaries.
\param[in] x, y, w, h Widget position and size
\param[in] numb Number of values
\param[in] entries Array of values
\param[in] min Lower boundary
\param[in] max Upper boundary
\param[in] autosize Whether the chart autosizes
\param[in] maxnumb Maximal number of entries
\param[in] textcolor Text color
*/
void Fl_Chart::draw_horbarchart(int x, int y, int w, int h, int numb, FL_CHART_ENTRY entries[],
double min, double max, int autosize, int maxnumb,
Fl_Color textcolor)
{
int i;
double lw = 0.0; /* Maximal label width */
/* Compute maximal label width */
for (i=0; i<numb; i++) {
double w1 = fl_width(entries[i].str);
if (w1 > lw) lw = w1;
double lw = 0.0; // Maximal label width
// Compute maximal label width
for (i = 0; i < numb; i++) {
double w1 = fl_width(entries[i].str);
if (w1 > lw)
lw = w1;
}
if (lw > 0.0) lw += 4.0;
if (lw > 0.0)
lw += 4.0;
double incr;
int zeroh;
if (max == min) incr = w;
else incr = w/(max-min);
if ( (-min*incr) < lw) {
incr = (w - lw + min*incr)/(max-min);
zeroh = x+(int)rint(lw);
if (max == min)
incr = w;
else
incr = w / (max - min);
if ((-min * incr) < lw) {
incr = (w - lw + min * incr) / (max - min);
zeroh = x + (int)rint(lw);
} else {
zeroh = (int)rint(x-min * incr);
zeroh = (int)rint(x - min * incr);
}
int bwidth = (int)rint(h/double(autosize?numb:maxnumb));
/* Draw base line */
int bwidth = (int)rint(h / double(autosize ? numb : maxnumb));
// Draw base line
fl_color(textcolor);
fl_line(zeroh, y, zeroh, y+h);
if (min == 0.0 && max == 0.0) return; /* Nothing else to draw */
/* Draw the bars */
for (i=0; i<numb; i++) {
int ww = (int)rint(entries[i].val*incr);
if (ww > 0)
fl_rectbound(zeroh,y+i*bwidth,ww+1,bwidth+1, (Fl_Color)entries[i].col);
else if (ww < 0)
fl_rectbound(zeroh+ww,y+i*bwidth,-ww+1,bwidth+1,(Fl_Color)entries[i].col);
fl_line(zeroh, y, zeroh, y + h);
if (min == 0.0 && max == 0.0)
return; // Nothing else to draw
// Draw the bars
for (i = 0; i < numb; i++) {
int ww = (int)rint(entries[i].val * incr);
if (ww > 0)
fl_rectbound(zeroh, y + i * bwidth, ww + 1, bwidth + 1, (Fl_Color)entries[i].col);
else if (ww < 0)
fl_rectbound(zeroh + ww, y + i * bwidth, -ww + 1, bwidth + 1, (Fl_Color)entries[i].col);
}
/* Draw the labels */
// Draw the labels
fl_color(textcolor);
for (i=0; i<numb; i++)
fl_draw(entries[i].str,
zeroh-2,y+i*bwidth+bwidth/2,0,0,
FL_ALIGN_RIGHT);
for (i = 0; i < numb; i++)
fl_draw(entries[i].str, zeroh - 2, y + i * bwidth + bwidth / 2, 0, 0, FL_ALIGN_RIGHT);
}
static void draw_linechart(int type, int x,int y,int w,int h,
int numb, FL_CHART_ENTRY entries[],
double min, double max, int autosize, int maxnumb,
Fl_Color textcolor)
/* Draws a line chart. x,y,w,h is the bounding box, entries the array of
numb entries and min and max the boundaries. */
/**
Draws a line chart.
\p x, \p y, \p w, \p h is the bounding box,
\p entries the array of \p numb entries,
and \p min and \p max the boundaries.
\param[in] x, y, w, h Widget position and size
\param[in] numb Number of values
\param[in] entries Array of values
\param[in] min Lower boundary
\param[in] max Upper boundary
\param[in] autosize Whether the chart autosizes
\param[in] maxnumb Maximal number of entries
\param[in] textcolor Text color
*/
void Fl_Chart::draw_linechart(int type, int x, int y, int w, int h, int numb,
FL_CHART_ENTRY entries[], double min, double max, int autosize,
int maxnumb, Fl_Color textcolor)
{
int i;
double lh = fl_height();
double incr;
if (max == min) incr = h-2.0*lh;
else incr = (h-2.0*lh)/ (max-min);
int zeroh = (int)rint(y+h-lh+min * incr);
double bwidth = w/double(autosize?numb:maxnumb);
/* Draw the values */
for (i=0; i<numb; i++) {
int x0 = x + (int)rint((i-.5)*bwidth);
int x1 = x + (int)rint((i+.5)*bwidth);
int yy0 = i ? zeroh - (int)rint(entries[i-1].val*incr) : 0;
int yy1 = zeroh - (int)rint(entries[i].val*incr);
if (type == FL_SPIKE_CHART) {
fl_color((Fl_Color)entries[i].col);
fl_line(x1, zeroh, x1, yy1);
} else if (type == FL_LINE_CHART && i != 0) {
fl_color((Fl_Color)entries[i-1].col);
fl_line(x0,yy0,x1,yy1);
} else if (type == FL_FILLED_CHART && i != 0) {
fl_color((Fl_Color)entries[i-1].col);
if ((entries[i-1].val>0.0)!=(entries[i].val>0.0)) {
double ttt = entries[i-1].val/(entries[i-1].val-entries[i].val);
int xt = x + (int)rint((i-.5+ttt)*bwidth);
fl_polygon(x0,zeroh, x0,yy0, xt,zeroh);
fl_polygon(xt,zeroh, x1,yy1, x1,zeroh);
} else {
fl_polygon(x0,zeroh, x0,yy0, x1,yy1, x1,zeroh);
}
fl_color(textcolor);
fl_line(x0,yy0,x1,yy1);
if (max == min)
incr = h - 2.0 * lh;
else
incr = (h - 2.0 * lh) / (max - min);
int zeroh = (int)rint(y + h - lh + min * incr);
double bwidth = w / double(autosize ? numb : maxnumb);
// Draw the values
for (i = 0; i < numb; i++) {
int x0 = x + (int)rint((i - .5) * bwidth);
int x1 = x + (int)rint((i + .5) * bwidth);
int yy0 = i ? zeroh - (int)rint(entries[i - 1].val * incr) : 0;
int yy1 = zeroh - (int)rint(entries[i].val * incr);
if (type == FL_SPIKE_CHART) {
fl_color((Fl_Color)entries[i].col);
fl_line(x1, zeroh, x1, yy1);
} else if (type == FL_LINE_CHART && i != 0) {
fl_color((Fl_Color)entries[i - 1].col);
fl_line(x0, yy0, x1, yy1);
} else if (type == FL_FILLED_CHART && i != 0) {
fl_color((Fl_Color)entries[i - 1].col);
if ((entries[i - 1].val > 0.0) != (entries[i].val > 0.0)) {
double ttt = entries[i - 1].val / (entries[i - 1].val - entries[i].val);
int xt = x + (int)rint((i - .5 + ttt) * bwidth);
fl_polygon(x0, zeroh, x0, yy0, xt, zeroh);
fl_polygon(xt, zeroh, x1, yy1, x1, zeroh);
} else {
fl_polygon(x0, zeroh, x0, yy0, x1, yy1, x1, zeroh);
}
fl_color(textcolor);
fl_line(x0, yy0, x1, yy1);
}
}
/* Draw base line */
// Draw base line
fl_color(textcolor);
fl_line(x,zeroh,x+w,zeroh);
/* Draw the labels */
for (i=0; i<numb; i++)
fl_draw(entries[i].str,
x+(int)rint((i+.5)*bwidth), zeroh - (int)rint(entries[i].val*incr),0,0,
entries[i].val>=0 ? FL_ALIGN_BOTTOM : FL_ALIGN_TOP);
fl_line(x, zeroh, x + w, zeroh);
// Draw the labels
for (i = 0; i < numb; i++)
fl_draw(entries[i].str, x + (int)rint((i + .5) * bwidth),
zeroh - (int)rint(entries[i].val * incr), 0, 0,
entries[i].val >= 0 ? FL_ALIGN_BOTTOM : FL_ALIGN_TOP);
}
static void draw_piechart(int x,int y,int w,int h,
int numb, FL_CHART_ENTRY entries[], int special,
Fl_Color textcolor)
/* Draws a pie chart. x,y,w,h is the bounding box, entries the array of
numb entries */
{
/**
Draws a pie chart.
\param[in] x,y,w,h bounding box
\param[in] numb number of chart entries
\param[in] entries array of chart entries
\param[in] special special (?)
\param[in] textcolor text color
*/
void Fl_Chart::draw_piechart(int x, int y, int w, int h, int numb, FL_CHART_ENTRY entries[],
int special, Fl_Color textcolor) {
int i;
double xc,yc,rad; /* center and radius */
double tot; /* sum of values */
double incr; /* increment in angle */
double curang; /* current angle we are drawing */
double txc,tyc; /* temporary center */
double xc, yc, rad; // center and radius
double tot; // sum of values
double incr; // increment in angle
double curang; // current angle we are drawing
double txc, tyc; // temporary center
double lh = fl_height();
/* compute center and radius */
// compute center and radius
double h_denom = (special ? 2.3 : 2.0);
rad = (h - 2*lh)/h_denom/1.1;
xc = x+w/2.0; yc = y+h-1.1*rad-lh;
/* compute sum of values */
rad = (h - 2 * lh) / h_denom / 1.1;
xc = x + w / 2.0;
yc = y + h - 1.1 * rad - lh;
// compute sum of values
tot = 0.0;
for (i=0; i<numb; i++)
if (entries[i].val > 0.0) tot += entries[i].val;
if (tot == 0.0) return;
incr = 360.0/tot;
/* Draw the pie */
curang = 0.0;
for (i=0; i<numb; i++)
for (i = 0; i < numb; i++) {
if (entries[i].val > 0.0)
{
txc = xc; tyc = yc;
/* Correct for special pies */
if (special && i==0)
{
txc += 0.3*rad*cos(ARCINC*(curang+0.5*incr*entries[i].val));
tyc -= 0.3*rad*sin(ARCINC*(curang+0.5*incr*entries[i].val));
tot += entries[i].val;
}
if (tot == 0.0)
return;
incr = 360.0 / tot;
// Draw the pie
curang = 0.0;
for (i = 0; i < numb; i++) {
if (entries[i].val > 0.0) {
txc = xc;
tyc = yc;
// Correct for special pies
if (special && i == 0) {
txc += 0.3 * rad * cos(ARCINC * (curang + 0.5 * incr * entries[i].val));
tyc -= 0.3 * rad * sin(ARCINC * (curang + 0.5 * incr * entries[i].val));
}
fl_color((Fl_Color)entries[i].col);
fl_begin_polygon(); fl_vertex(txc,tyc);
fl_arc(txc,tyc,rad,curang, curang+incr*entries[i].val);
fl_begin_polygon();
fl_vertex(txc, tyc);
fl_arc(txc, tyc, rad, curang, curang + incr * entries[i].val);
fl_end_polygon();
fl_color(textcolor);
fl_begin_loop(); fl_vertex(txc,tyc);
fl_arc(txc,tyc,rad,curang, curang+incr*entries[i].val);
fl_begin_loop();
fl_vertex(txc, tyc);
fl_arc(txc, tyc, rad, curang, curang + incr * entries[i].val);
fl_end_loop();
curang += 0.5 * incr * entries[i].val;
/* draw the label */
double xl = txc + 1.1*rad*cos(ARCINC*curang);
fl_draw(entries[i].str,
(int)rint(xl),
(int)rint(tyc - 1.1*rad*sin(ARCINC*curang)),
0, 0,
xl<txc ? FL_ALIGN_RIGHT : FL_ALIGN_LEFT);
// draw the label
double xl = txc + 1.1 * rad * cos(ARCINC * curang);
fl_draw(entries[i].str, (int)rint(xl), (int)rint(tyc - 1.1 * rad * sin(ARCINC * curang)), 0,
0, xl < txc ? FL_ALIGN_RIGHT : FL_ALIGN_LEFT);
curang += 0.5 * incr * entries[i].val;
}
}
}
/**
Draws the Fl_Chart widget.
*/
void Fl_Chart::draw() {
draw_box();
Fl_Boxtype b = box();
int xx = x()+Fl::box_dx(b); // was 9 instead of dx...
int yy = y()+Fl::box_dy(b);
int ww = w()-Fl::box_dw(b);
int hh = h()-Fl::box_dh(b);
fl_push_clip(xx, yy, ww, hh);
draw_box();
Fl_Boxtype b = box();
int xx = x() + Fl::box_dx(b); // was 9 instead of dx...
int yy = y() + Fl::box_dy(b);
int ww = w() - Fl::box_dw(b);
int hh = h() - Fl::box_dh(b);
fl_push_clip(xx, yy, ww, hh);
ww--; hh--; // adjust for line thickness
ww--;
hh--; // adjust for line thickness
if (min >= max) {
min = max = 0.0;
for (int i=0; i<numb; i++) {
if (entries[i].val < min) min = entries[i].val;
if (entries[i].val > max) max = entries[i].val;
}
if (min >= max) {
min = max = 0.0;
for (int i = 0; i < numb; i++) {
if (entries[i].val < min)
min = entries[i].val;
if (entries[i].val > max)
max = entries[i].val;
}
}
fl_font(textfont(),textsize());
fl_font(textfont(), textsize());
switch (type()) {
switch (type()) {
case FL_BAR_CHART:
ww++; // makes the bars fill box correctly
draw_barchart(xx,yy,ww,hh, numb, entries, min, max,
autosize(), maxnumb, textcolor());
break;
ww++; // makes the bars fill box correctly
draw_barchart(xx, yy, ww, hh, numb, entries, min, max, autosize(), maxnumb, textcolor());
break;
case FL_HORBAR_CHART:
hh++; // makes the bars fill box correctly
draw_horbarchart(xx,yy,ww,hh, numb, entries, min, max,
autosize(), maxnumb, textcolor());
break;
hh++; // makes the bars fill box correctly
draw_horbarchart(xx, yy, ww, hh, numb, entries, min, max, autosize(), maxnumb, textcolor());
break;
case FL_PIE_CHART:
draw_piechart(xx,yy,ww,hh,numb,entries,0, textcolor());
break;
draw_piechart(xx, yy, ww, hh, numb, entries, 0, textcolor());
break;
case FL_SPECIALPIE_CHART:
draw_piechart(xx,yy,ww,hh,numb,entries,1,textcolor());
break;
draw_piechart(xx, yy, ww, hh, numb, entries, 1, textcolor());
break;
default:
draw_linechart(type(),xx,yy,ww,hh, numb, entries, min, max,
autosize(), maxnumb, textcolor());
break;
}
draw_label();
fl_pop_clip();
draw_linechart(type(), xx, yy, ww, hh, numb, entries, min, max, autosize(), maxnumb,
textcolor());
break;
}
draw_label();
fl_pop_clip();
}
/*------------------------------*/
#define FL_CHART_BOXTYPE FL_BORDER_BOX
#define FL_CHART_COL1 FL_COL1
#define FL_CHART_LCOL FL_LCOL
#define FL_CHART_ALIGN FL_ALIGN_BOTTOM
/**
Create a new Fl_Chart widget using the given position, size and label string.
The default boxstyle is \c FL_NO_BOX.
\param[in] X, Y, W, H position and size of the widget
\param[in] L widget label, default is no label
*/
Fl_Chart::Fl_Chart(int X, int Y, int W, int H,const char *L) :
Fl_Widget(X,Y,W,H,L) {
*/
Fl_Chart::Fl_Chart(int X, int Y, int W, int H, const char *L)
: Fl_Widget(X, Y, W, H, L) {
box(FL_BORDER_BOX);
align(FL_ALIGN_BOTTOM);
numb = 0;
maxnumb = 0;
sizenumb = FL_CHART_MAX;
autosize_ = 1;
min = max = 0;
textfont_ = FL_HELVETICA;
textsize_ = 10;
numb = 0;
maxnumb = 0;
sizenumb = FL_CHART_MAX;
autosize_ = 1;
min = max = 0;
textfont_ = FL_HELVETICA;
textsize_ = 10;
textcolor_ = FL_FOREGROUND_COLOR;
entries = (FL_CHART_ENTRY *)calloc(sizeof(FL_CHART_ENTRY), FL_CHART_MAX + 1);
entries = (FL_CHART_ENTRY *)calloc(sizeof(FL_CHART_ENTRY), FL_CHART_MAX + 1);
}
/**
Destroys the Fl_Chart widget and all of its data.
*/
*/
Fl_Chart::~Fl_Chart() {
free(entries);
}
/**
Removes all values from the chart.
*/
*/
void Fl_Chart::clear() {
numb = 0;
min = max = 0;
@ -312,14 +369,15 @@ void Fl_Chart::clear() {
}
/**
Add the data value \p val with optional label \p str and color \p col
Adds the data value \p val with optional label \p str and color \p col
to the chart.
\param[in] val data value
\param[in] str optional data label
\param[in] col optional data color
*/
*/
void Fl_Chart::add(double val, const char *str, unsigned col) {
/* Allocate more entries if required */
// Allocate more entries if required
if (numb >= sizenumb) {
sizenumb += FL_CHART_MAX;
entries = (FL_CHART_ENTRY *)realloc(entries, sizeof(FL_CHART_ENTRY) * (sizenumb + 1));
@ -327,73 +385,82 @@ void Fl_Chart::add(double val, const char *str, unsigned col) {
// Shift entries as needed
if (numb >= maxnumb && maxnumb > 0) {
memmove(entries, entries + 1, sizeof(FL_CHART_ENTRY) * (numb - 1));
numb --;
numb--;
}
entries[numb].val = float(val);
entries[numb].col = col;
if (str) {
strlcpy(entries[numb].str,str,FL_CHART_LABEL_MAX + 1);
} else {
entries[numb].str[0] = 0;
}
if (str) {
strlcpy(entries[numb].str, str, FL_CHART_LABEL_MAX + 1);
} else {
entries[numb].str[0] = 0;
}
numb++;
redraw();
}
/**
Inserts a data value \p val at the given position \p ind.
Position 1 is the first data value.
\param[in] ind insertion position
\param[in] val data value
\param[in] str optional data label
\param[in] col optional data color
*/
*/
void Fl_Chart::insert(int ind, double val, const char *str, unsigned col) {
int i;
if (ind < 1 || ind > numb+1) return;
/* Allocate more entries if required */
if (ind < 1 || ind > numb + 1)
return;
// Allocate more entries if required
if (numb >= sizenumb) {
sizenumb += FL_CHART_MAX;
entries = (FL_CHART_ENTRY *)realloc(entries, sizeof(FL_CHART_ENTRY) * (sizenumb + 1));
}
// Shift entries as needed
for (i=numb; i >= ind; i--) entries[i] = entries[i-1];
if (numb < maxnumb || maxnumb == 0) numb++;
/* Fill in the new entry */
entries[ind-1].val = float(val);
entries[ind-1].col = col;
for (i = numb; i >= ind; i--)
entries[i] = entries[i - 1];
if (numb < maxnumb || maxnumb == 0)
numb++;
// Fill in the new entry
entries[ind - 1].val = float(val);
entries[ind - 1].col = col;
if (str) {
strlcpy(entries[ind-1].str,str,FL_CHART_LABEL_MAX+1);
strlcpy(entries[ind - 1].str, str, FL_CHART_LABEL_MAX + 1);
} else {
entries[ind-1].str[0] = 0;
entries[ind - 1].str[0] = 0;
}
redraw();
}
/**
Replace a data value \p val at the given position \p ind.
Replaces a data value \p val at the given position \p ind.
Position 1 is the first data value.
\param[in] ind insertion position
\param[in] val data value
\param[in] str optional data label
\param[in] col optional data color
*/
void Fl_Chart::replace(int ind,double val, const char *str, unsigned col) {
if (ind < 1 || ind > numb) return;
entries[ind-1].val = float(val);
entries[ind-1].col = col;
*/
void Fl_Chart::replace(int ind, double val, const char *str, unsigned col) {
if (ind < 1 || ind > numb)
return;
entries[ind - 1].val = float(val);
entries[ind - 1].col = col;
if (str) {
strlcpy(entries[ind-1].str,str,FL_CHART_LABEL_MAX+1);
strlcpy(entries[ind - 1].str, str, FL_CHART_LABEL_MAX + 1);
} else {
entries[ind-1].str[0] = 0;
entries[ind - 1].str[0] = 0;
}
redraw();
}
/**
Sets the lower and upper bounds of the chart values.
\param[in] a, b are used to set lower, upper
*/
*/
void Fl_Chart::bounds(double a, double b) {
this->min = a;
this->max = b;
@ -401,21 +468,24 @@ void Fl_Chart::bounds(double a, double b) {
}
/**
Set the maximum number of data values for a chart.
Sets the maximum number of data values for a chart.
If you do not call this method then the chart will be allowed to grow
to any size depending on available memory.
\param[in] m maximum number of data values allowed.
*/
*/
void Fl_Chart::maxsize(int m) {
int i;
/* Fill in the new number */
if (m < 0) return;
// Fill in the new number
if (m < 0)
return;
maxnumb = m;
/* Shift entries if required */
// Shift entries if required
if (numb > maxnumb) {
for (i = 0; i<maxnumb; i++)
entries[i] = entries[i+numb-maxnumb];
numb = maxnumb;
redraw();
for (i = 0; i < maxnumb; i++)
entries[i] = entries[i + numb - maxnumb];
numb = maxnumb;
redraw();
}
}