exploring the window class [fltk]

Bjarne Stroustrup “Programming Principles and Practice Using C++”
Chapter 16 Exercise 1
Using GUI library called FLTK (Fast Light Tool Kit, “full tick”).

Output:

//  Philipp Siedler
//  Bjarne Stroustrup's PP
//  Chapter 16 Exercise 1

#define _USE_MATH_DEFINES
#include "Simple_window.h"
#include "Graph.h"
#include <cmath>
#include "GUI.h"

// layout
constexpr int xmax = 600;
constexpr int ymax = 400;

struct My_window : Window {
	My_window(Point xy, int w, int h, const string& title)
		: Window(xy, w, h, title),
		next_button_pushed(false),
		next_button(Point(x_max() - 140, 0), 70, 20, "Next", cb_next),
		quit_button_pushed(false),
		quit_button(Point(x_max() - 70, 0), 70, 20, "Quit", cb_quit)
	{
		attach(next_button);
		attach(quit_button);
	}

	void wait_for_button()
		// modified event loop
		// handle all events (as per default), but quit when button_pushed becomes true
		// this allows graphics without control inversion
	{
		while (!next_button_pushed) Fl::wait();
		next_button_pushed = false;
		Fl::redraw();
	}

	Button next_button;
	Button quit_button;

private:
	bool next_button_pushed;
	bool quit_button_pushed;

	static void cb_next(Address, Address addr) // callback for next_button
											   //	{ reference_to<Simple_window>(addr).next(); }
	{
		reference_to<My_window>(addr).next();
	}

	static void cb_quit(Address, Address addr) // callback for quit_button
											   //	{ reference_to<Simple_window>(addr).quit(); }
	{
		reference_to<My_window>(addr).quit();
	}

	void next() { next_button_pushed = true; }
	void quit() { hide(); }
};

int main()
try
{
	My_window win(Point(100, 100), xmax, ymax, "quit+next");
	return gui_main();
}
catch (exception& e) {
	cerr << "error: " << e.what() << '\n';
	keep_window_open();
	return 1;
}

catch (...) {
	cerr << "Unknown exception!\n";
	keep_window_open();
	return 2;
}

line drawing program + color & linestyle menu [fltk]

Bjarne Stroustrup “Programming Principles and Practice Using C++”
Chapter 16 Drill 4
Using GUI library called FLTK (Fast Light Tool Kit, “full tick”).

Output:

//  Philipp Siedler
//  Bjarne Stroustrup's PP
//  Chapter 16 Drill 4

#define _USE_MATH_DEFINES
#include "Simple_window.h"
#include "Graph.h"
#include <cmath>
#include "GUI.h"

// layout
constexpr int xmax = 600;
constexpr int ymax = 400;

struct Lines_window : Window {
	Lines_window(Point xy, int w, int h, const string& title);
private:
	// data
	Open_polyline lines;

	// widgets
	Button next_button;	// add (next_x, next_y) to lines
	Button quit_button;	// end program
	In_box next_x;
	In_box next_y;
	Out_box xy_out;

	// color menu
	Menu color_menu;
	Button color_menu_button;
	void change_color(Color c) { lines.set_color(c); }
	void hide_color_menu() { color_menu.hide(); color_menu_button.show(); }

	// line style menu
	Menu line_style_menu;
	Button line_style_menu_button;
	void change_line_style(Line_style ls) { lines.set_style(ls); }
	void hide_line_style_menu() { line_style_menu.hide(); line_style_menu_button.show(); }

	// actions invoked by callbacks
	// color menu
	void red_pressed() { change_color(Color::red); hide_color_menu(); }
	void blue_pressed() { change_color(Color::blue); hide_color_menu(); }
	void black_pressed() { change_color(Color::black); hide_color_menu(); }
	void color_menu_pressed() { color_menu_button.hide(); color_menu.show(); }

	// line style menu
	void solid_pressed() { change_line_style(Line_style::solid); hide_line_style_menu(); }
	void dashed_pressed() { change_line_style(Line_style::dash); hide_line_style_menu(); }
	void dotted_pressed() { change_line_style(Line_style::dot); hide_line_style_menu(); }
	void line_style_menu_pressed() { line_style_menu_button.hide(); line_style_menu.show(); }

	void next();
	void quit();

	// callback functions
	// color
	static void cb_red(Address, Address);
	static void cb_blue(Address, Address);
	static void cb_black(Address, Address);
	static void cb_color_menu(Address, Address);

	// line style
	static void cb_solid(Address, Address);
	static void cb_dash(Address, Address);
	static void cb_dot(Address, Address);
	static void cb_line_style_menu(Address, Address);

	static void cb_next(Address, Address);
	static void cb_quit(Address, Address);
};

Lines_window::Lines_window(Point xy, int w, int h, const string& title)
	:Window(xy, w, h, title),
	next_button(Point(x_max() - 150, 0), 70, 20, "Next point", cb_next),
	quit_button(Point(x_max() - 70, 0), 70, 20, "Quit", cb_quit),
	next_x(Point(x_max() - 310, 0), 50, 20, "next x:"),
	next_y(Point(x_max() - 210, 0), 50, 20, "next y:"),
	xy_out(Point(100, 0), 100, 20, "current (x,y):"),
	color_menu(Point(x_max() - 70, 30), 70, 20, Menu::vertical, "color"),
	color_menu_button(Point(x_max() - 80, 30), 80, 20, "color menu", cb_color_menu),
	line_style_menu(Point(x_max() - 70, 90), 70, 20, Menu::vertical, "line style"),
	line_style_menu_button(Point(x_max() - 80, 90), 80, 20, "style menu", cb_line_style_menu)
{
	attach(next_button);
	attach(quit_button);
	attach(next_x);
	attach(next_y);
	attach(xy_out);

	// initialize out box and line color
	xy_out.put("no point");
	lines.set_color(Color::black);

	color_menu.attach(new Button(Point(0, 0), 0, 0, "red", cb_red));
	color_menu.attach(new Button(Point(0, 0), 0, 0, "blue", cb_blue));
	color_menu.attach(new Button(Point(0, 0), 0, 0, "black", cb_black));

	line_style_menu.attach(new Button(Point(0, 0), 0, 0, "solid", cb_solid));
	line_style_menu.attach(new Button(Point(0, 0), 0, 0, "dashed", cb_dash));
	line_style_menu.attach(new Button(Point(0, 0), 0, 0, "dotted", cb_dot));

	attach(color_menu);
	attach(line_style_menu);

	color_menu.hide();
	line_style_menu.hide();

	attach(line_style_menu_button);
	attach(color_menu_button);
	attach(lines);
}

void Lines_window::next()
{
	int x = next_x.get_int();
	int y = next_y.get_int();

	lines.add(Point(x, y));

	// update current position readout
	ostringstream ss;
	ss << '(' << x << ',' << y << ')';
	xy_out.put(ss.str());

	redraw();
}

void Lines_window::quit()
{
	hide();
}

// color callback
void Lines_window::cb_red(Address, Address pw)
{
	reference_to<Lines_window>(pw).red_pressed();
}

void Lines_window::cb_blue(Address, Address pw)
{
	reference_to<Lines_window>(pw).blue_pressed();
}

void Lines_window::cb_black(Address, Address pw)
{
	reference_to<Lines_window>(pw).black_pressed();
}

void Lines_window::cb_color_menu(Address, Address pw)
{
	reference_to<Lines_window>(pw).color_menu_pressed();
}

// line style callback
void Lines_window::cb_solid(Address, Address pw)
{
	reference_to<Lines_window>(pw).solid_pressed();
}

void Lines_window::cb_dash(Address, Address pw)
{
	reference_to<Lines_window>(pw).dashed_pressed();
}

void Lines_window::cb_dot(Address, Address pw)
{
	reference_to<Lines_window>(pw).dotted_pressed();
}

void Lines_window::cb_line_style_menu(Address, Address pw)
{
	reference_to<Lines_window>(pw).line_style_menu_pressed();
}

// next + quit callback
void Lines_window::cb_next(Address, Address pw)
{
	reference_to<Lines_window>(pw).next();
}

void Lines_window::cb_quit(Address, Address pw)
{
	reference_to<Lines_window>(pw).quit();
}

int main()
try
{
	Lines_window win(Point(100, 100), xmax, ymax, "lines");
	return gui_main();
}
catch (exception& e) {
	cerr << "error: " << e.what() << '\n';
	keep_window_open();
	return 1;
}

catch (...) {
	cerr << "Unknown exception!\n";
	keep_window_open();
	return 2;
}

line drawing program + color menu [fltk]

Bjarne Stroustrup “Programming Principles and Practice Using C++”
Chapter 16 Drill 3
Using GUI library called FLTK (Fast Light Tool Kit, “full tick”).

Output:

//  Philipp Siedler
//  Bjarne Stroustrup's PP
//  Chapter 16 Drill 3

#define _USE_MATH_DEFINES
#include "Simple_window.h"
#include "Graph.h"
#include <cmath>
#include "GUI.h"

// layout
constexpr int xmax = 600;
constexpr int ymax = 400;

struct Lines_window : Window {
	Lines_window(Point xy, int w, int h, const string& title);
private:
	// data
	Open_polyline lines;

	// widgets
	Button next_button;	// add (next_x, next_y) to lines
	Button quit_button;	// end program
	In_box next_x;
	In_box next_y;
	Out_box xy_out;
	Menu color_menu;
	Button menu_button;

	void change(Color c) { lines.set_color(c); }

	void hide_menu() { color_menu.hide(); menu_button.show(); }

	// actions invoked by callbacks
	void red_pressed() { change(Color::red); hide_menu(); }
	void blue_pressed() { change(Color::blue); hide_menu(); }
	void black_pressed() { change(Color::black); hide_menu(); }
	void menu_pressed() { menu_button.hide(); color_menu.show(); }
	void next();
	void quit();

	// callback functions
	static void cb_red(Address, Address);
	static void cb_blue(Address, Address);
	static void cb_black(Address, Address);
	static void cb_menu(Address, Address);
	static void cb_next(Address, Address);
	static void cb_quit(Address, Address);
};

Lines_window::Lines_window(Point xy, int w, int h, const string& title)
	:Window(xy, w, h, title),
	next_button(Point(x_max() - 150, 0), 70, 20, "Next point", cb_next),
	quit_button(Point(x_max() - 70, 0), 70, 20, "Quit", cb_quit),
	next_x(Point(x_max() - 310, 0), 50, 20, "next x:"),
	next_y(Point(x_max() - 210, 0), 50, 20, "next y:"),
	xy_out(Point(100, 0), 100, 20, "current (x,y):"),
	color_menu(Point(x_max() - 70, 30), 70, 20, Menu::vertical, "color"),
	menu_button(Point(x_max() - 80, 30), 80, 20, "color menu", cb_menu)
{
	attach(next_button);
	attach(quit_button);
	attach(next_x);
	attach(next_y);
	attach(xy_out);
	xy_out.put("no point");
	color_menu.attach(new Button(Point(0, 0), 0, 0, "red", cb_red));
	color_menu.attach(new Button(Point(0, 0), 0, 0, "blue", cb_blue));
	color_menu.attach(new Button(Point(0, 0), 0, 0, "black", cb_black));
	attach(color_menu);
	color_menu.hide();
	attach(menu_button);
	attach(lines);
}

void Lines_window::next()
{
	int x = next_x.get_int();
	int y = next_y.get_int();

	lines.add(Point(x, y));

	// update current position readout
	ostringstream ss;
	ss << '(' << x << ',' << y << ')';
	xy_out.put(ss.str());

	redraw();
}

void Lines_window::quit()
{
	hide();
}

void Lines_window::cb_red(Address, Address pw)
{
	reference_to<Lines_window>(pw).red_pressed();
}

void Lines_window::cb_blue(Address, Address pw)
{
	reference_to<Lines_window>(pw).blue_pressed();
}

void Lines_window::cb_black(Address, Address pw)
{
	reference_to<Lines_window>(pw).black_pressed();
}

void Lines_window::cb_menu(Address, Address pw)
{
	reference_to<Lines_window>(pw).menu_pressed();
}

void Lines_window::cb_next(Address, Address pw)
{
	reference_to<Lines_window>(pw).next();
}

void Lines_window::cb_quit(Address, Address pw)
{
	reference_to<Lines_window>(pw).quit();
}

int main()
try
{
	Lines_window win(Point(100, 100), xmax, ymax, "lines");
	return gui_main();
}
catch (exception& e) {
	cerr << "error: " << e.what() << '\n';
	keep_window_open();
	return 1;
}

catch (...) {
	cerr << "Unknown exception!\n";
	keep_window_open();
	return 2;
}

line drawing program [fltk]

Bjarne Stroustrup “Programming Principles and Practice Using C++”
Chapter 16 Drill 2
Using GUI library called FLTK (Fast Light Tool Kit, “full tick”).

Output:

//  Philipp Siedler
//  Bjarne Stroustrup's PP
//  Chapter 16 Drill 2

#define _USE_MATH_DEFINES
#include "Simple_window.h"
#include "Graph.h"
#include <cmath>
#include "GUI.h"

// layout
constexpr int xmax = 600;
constexpr int ymax = 400;

struct Lines_window : Window {
	Lines_window(Point xy, int w, int h, const string& title);
private:
	// data
	Open_polyline lines;

	// widgets
	Button next_button;	// add (next_x, next_y) to lines
	Button quit_button;	// end program
	In_box next_x;
	In_box next_y;
	Out_box xy_out;

	// actions invoked by callbacks
	void next();
	void quit();

	// callback functions
	static void cb_next(Address, Address);
	static void cb_quit(Address, Address);
};

Lines_window::Lines_window(Point xy, int w, int h, const string& title)
	:Window(xy, w, h, title),
	next_button(Point(x_max() - 150, 0), 70, 20, "Next point", cb_next),
	quit_button(Point(x_max() - 70, 0), 70, 20, "Quit", cb_quit),
	next_x(Point(x_max() - 310, 0), 50, 20, "next x:"),
	next_y(Point(x_max() - 210, 0), 50, 20, "next y:"),
	xy_out(Point(100, 0), 100, 20, "current (x,y):")
{
	attach(next_button);
	attach(quit_button);
	attach(next_x);
	attach(next_y);
	attach(xy_out);
	xy_out.put("no point");
	lines.set_color(Color::black);
	attach(lines);
}

void Lines_window::next()
{
	int x = next_x.get_int();
	int y = next_y.get_int();

	lines.add(Point(x, y));

	// update current position readout
	ostringstream ss;
	ss << '(' << x << ',' << y << ')';
	xy_out.put(ss.str());

	redraw();
}

void Lines_window::quit()
{
	hide();
}

void Lines_window::cb_next(Address, Address pw)
{
	reference_to<Lines_window>(pw).next();
}

void Lines_window::cb_quit(Address, Address pw)
{
	reference_to<Lines_window>(pw).quit();
}

int main()
try
{
	Lines_window win(Point(100, 100), xmax, ymax, "lines");
	return gui_main();
}
catch (exception& e) {
	cerr << "error: " << e.what() << '\n';
	keep_window_open();
	return 1;
}

catch (...) {
	cerr << "Unknown exception!\n";
	keep_window_open();
	return 2;
}

Graphical user interface – Fast Light Toolkit [FLTK]

What is FLTK? As described on fltk.org:

“FLTK (pronounced “fulltick”) is a cross-platform C++ GUI toolkit for UNIX®/Linux® (X11), Microsoft® Windows®, and MacOS® X. FLTK provides modern GUI functionality without the bloat and supports 3D graphics via OpenGL® and its built-in GLUT emulation.
FLTK is designed to be small and modular enough to be statically linked, but works fine as a shared library. FLTK also includes an excellent UI builder called FLUID that can be used to create applications in minutes.”

Download FLTK here.

How to install FLTK under Visual Stduio 2017 Community
How to compile FLTK – [following the instruction of fltk.org] This approach apparently prevents cross-contamination. Instead of copying files and folders from fltk-1.3.4 to the Visual Studio Community 2017 folder structure, the include and library paths are propperly (I hope so!) added to the project.
How to compile FLTK – [following the instruction of Principles and Practice using C++]

FLTK Examples:
Chapter 12 – A Display Model [using FLTK]
Chapter 13 – Graphics Classes [using FLTK]
Chapter 14 – Graphics Class Design [using FLTK]
Chapter 15 – Graphing Functions and Data [using FLTK]
Chapter 16 – Graphical User Interface [using FLTK]

Average temperature data of Cambridge, England and Cambridge, Massachusetts graphing [fltk]

Bjarne Stroustrup “Programming Principles and Practice Using C++”
Chapter 15 Exercise 11
Using GUI library called FLTK (Fast Light Tool Kit, “full tick”).

Output:

//  Philipp Siedler
//  Bjarne Stroustrup's PP
//  Chapter 15 Exercise 11

#define _USE_MATH_DEFINES
#include "Simple_window.h"
#include "Graph.h"
#include <cmath>

ostream& operator<<(ostream& out, Point& a) {
	out << "(" << a.x << "," << a.y << ")";
	return out;
}

// layout
constexpr int xmax = 600;
constexpr int ymax = 600;

constexpr int x_orig = xmax / 2;
constexpr int y_orig = ymax / 2;
Point orig(x_orig, y_orig);

constexpr int r_min = -10;
constexpr int r_max = 10;

constexpr int n_points = 400;

constexpr int x_scale = 2;
constexpr int y_scale = 2;

constexpr int xoffset = 100;
constexpr int yoffset = 100;

constexpr int xspace = 100;
constexpr int yspace = 100;

constexpr int xlength = xmax - xoffset - xspace;
constexpr int ylength = ymax - yoffset - yspace;


int main()
try
{
	Point tl(100, 100);
	Simple_window win(tl, xmax, ymax, "Function graphs");

	// x axis
	Axis x(Axis::x, Point(xoffset, ymax - yoffset), xlength, 12,
		"month    Jan  Feb   Mar  Apr  May  Jun   Jul    Aug  Sep  Oct  Nov   Dec");
	x.set_color(Color::black);
	x.label.move(-100, 0);
	win.attach(x);

	// y axis
	Axis y(Axis::y, Point(yoffset, ymax - yoffset), ylength, 20, "temperature in 0 - 20 C");
	y.set_color(Color::black);
	win.attach(y);

	// data
	// Cambridge, England monthly normal weather 2016
	vector<double> camb_eng_temp = { 
		3.7,
		3.8,
		6.1,
		8.0,
		11.4,
		14.3,
		16.8,
		16.9,
		14.1,
		10.5,
		6.5,
		4.7
	};

	// Cambridge, Massachusetts monthly normal weather 2016
	vector<double> camb_mas_temp = {
		-1.9,
		-0.9,
		3.7,
		8.9,
		14.6,
		19.8,
		23.1,
		22.2,
		18.2,
		12.7,
		7.4,
		0.9
	};

	// graph
	Open_polyline cet; // Cambridge, England
	Open_polyline cmt; // Cambridge, Massachusetts

	for (int i = 0; i < 12; i++) {
		cet.add(Point(xoffset + i * (xlength / 12), (yspace + ylength) - camb_eng_temp[i] * 20));
		cmt.add(Point(xoffset + i * (xlength / 12), (yspace + ylength) - camb_mas_temp[i] * 20));
	}

	cet.set_color(Color::red);
	win.attach(cet);

	cmt.set_color(Color::blue);
	win.attach(cmt);

	win.wait_for_button();
	keep_window_open();
}
catch (exception& e) {
	cerr << "error: " << e.what() << '\n';
	keep_window_open();
	return 1;
}

catch (...) {
	cerr << "Unknown exception!\n";
	keep_window_open();
	return 2;
}

labeled points data graphing [fltk]

Bjarne Stroustrup “Programming Principles and Practice Using C++”
Chapter 15 Exercise 10
Using GUI library called FLTK (Fast Light Tool Kit, “full tick”).

Output:

//  Philipp Siedler
//  Bjarne Stroustrup's PP
//  Chapter 15 Exercise 10

#define _USE_MATH_DEFINES
#include "Simple_window.h"
#include "Graph.h"
#include <cmath>

ostream& operator<<(ostream& out, Point& a) {
	out << "(" << a.x << "," << a.y << ")";
	return out;
}

// layout
constexpr int xmax = 600;
constexpr int ymax = 600;

constexpr int x_orig = xmax / 2;
constexpr int y_orig = ymax / 2;
Point orig(x_orig, y_orig);

constexpr int r_min = -10;
constexpr int r_max = 10;

constexpr int n_points = 400;

constexpr int x_scale = 2;
constexpr int y_scale = 2;

constexpr int xoffset = 100;
constexpr int yoffset = 100;

constexpr int xspace = 100;
constexpr int yspace = 100;

constexpr int xlength = xmax - xoffset - xspace;
constexpr int ylength = ymax - yoffset - yspace;

class bar_graph : public Shape
{
public:
	bar_graph(Point origin, vector<Point>& data, int x_scale, int r1_min, int r1_max, int y_scale, int r2_min, int r2_max, Color col, string label);

	void draw_lines() const;

	vector<Point>& get_data() { return data; }

private:
	Point origin;
	vector<Point>& data;

	int x_scale;
	int r1_min;
	int r1_max;

	int y_scale;
	int r2_min;
	int r2_max;

	int bar_width;

	Color col;
	string label;
};

bar_graph::bar_graph(Point origin, vector<Point>& data, int x_scale, int r1_min, int r1_max, int y_scale, int r2_min, int r2_max, Color col, string label)
	: origin(origin),
	data(data),
	x_scale(x_scale),
	r1_min(r1_min),
	r1_max(r1_max),
	y_scale(y_scale),
	r2_min(r2_min),
	r2_max(r2_max),
	bar_width(bar_width),
	col(col),
	label(label)
{

}

void bar_graph::draw_lines() const
{
	int ds = data.size();
	cout << ds << endl;


	for (int i = 0; i < data.size(); i++) {

		int h = data[i].x;
		int c = data[i].y;

		// scale factor
		double sx = (xlength / 2.0) / (r1_max - r1_min);
		double sy = (ylength / 2.0) / (r2_max - r2_min);

		// draw point
		Point p(origin.x + (h - r1_min) * sx, origin.y - (c - r2_min) * sy);
		cout << p << endl;

		Graph_lib::Circle crcl(p, 3);
		crcl.set_color(col);
		crcl.set_fill_color(col);
		crcl.draw();

		// draw label
		string point_label = "(" + to_string(data[i].x) + "," + to_string(data[i].y) + ")";
		Text l(p, point_label);
		l.set_color(Color::red);

		l.draw();

	}

	// graph label
	Text gl(Point(origin.x - 90, origin.y + 15), label);
	gl.set_color(col);

	gl.draw();
}

int main()
try
{
	Point tl(100, 100);
	Simple_window win(tl, xmax, ymax, "Function graphs.");

	int r1_min = 170;
	int r1_max = 180;

	int r2_min = 7;
	int r2_max = 23;

	// notch label x
	string x_notch = "1 == " + to_string((r1_max - r1_min) / 10);

	// notch label y
	ostringstream strs;
	strs << setprecision(2) << (r2_max - r2_min) / 10.0;
	string y_notch = "1 == " + strs.str();

	// x axis
	Axis x(Axis::x, Point(orig.x - 200, orig.y), 400, 20, x_notch);
	x.set_color(Color::black);
	win.attach(x);

	// y axis
	Axis y(Axis::y, Point(orig.x, orig.y + 200), 400, 20, y_notch);
	y.set_color(Color::black);
	win.attach(y);

	// people height data
	vector<Point> d = {
		Point(170, 7),
		Point(175, 9),
		Point(180, 23),
		Point(173, 8),
		Point(178, 20),
		Point(177, 15),
		Point(171, 10),
		Point(174, 19)
	};

	// bar graph
	bar_graph bg(orig, d, x_scale, r1_min, r1_max, y_scale, r2_min, r2_max, Color::blue, "labeled points");
	win.attach(bg);

	win.wait_for_button();
	keep_window_open();
}
catch (exception& e) {
	cerr << "error: " << e.what() << '\n';
	keep_window_open();
	return 1;
}

catch (...) {
	cerr << "Unknown exception!\n";
	keep_window_open();
	return 2;
}

bar graph – group of people height data graphing [fltk]

Bjarne Stroustrup “Programming Principles and Practice Using C++”
Chapter 15 Exercise 8
Using GUI library called FLTK (Fast Light Tool Kit, “full tick”).

Output:

//  Philipp Siedler
//  Bjarne Stroustrup's PP
//  Chapter 15 Exercise 8

#define _USE_MATH_DEFINES
#include "Simple_window.h"
#include "Graph.h"
#include <cmath>

ostream& operator<<(ostream& out, Point& a) {
	out << "(" << a.x << "," << a.y << ")";
	return out;
}

// layout
constexpr int xmax = 600;
constexpr int ymax = 600;

constexpr int x_orig = xmax / 2;
constexpr int y_orig = ymax / 2;
Point orig(x_orig, y_orig);

constexpr int r_min = -10;
constexpr int r_max = 10;

constexpr int n_points = 400;

constexpr int x_scale = 2;
constexpr int y_scale = 2;

constexpr int xoffset = 100;
constexpr int yoffset = 100;

constexpr int xspace = 100;
constexpr int yspace = 100;

constexpr int xlength = xmax - xoffset - xspace;
constexpr int ylength = ymax - yoffset - yspace;

struct ppl_height
{
	ppl_height(double height, int count)
		:height(height), count(count) {	}
	double height;
	int count;
};

void read_data(string location, vector<ppl_height>& v)
{
	ifstream ist(location);
	if (!ist) { error("no such file exists", location); }

	char comma;
	double height;
	int count;

	while (ist >> height >> comma >> count)
	{
		if (ist.eof()) {
			break;
		}
		v.push_back(ppl_height(height, count));
	}

}

class bar_graph : public Shape
{
public:
	bar_graph(Point origin, vector<ppl_height>& data, int x_scale, int r1_min, int r1_max, int y_scale, int r2_min, int r2_max, int bar_width, Color col, string label);

	void draw_lines() const;

	vector<ppl_height>& get_data() { return data; }

private:
	Point origin;
	vector<ppl_height>& data;

	int x_scale;
	int r1_min;
	int r1_max;

	int y_scale;
	int r2_min;
	int r2_max;

	int bar_width;

	Color col;
	string label;
};

bar_graph::bar_graph(Point origin, vector<ppl_height>& data, int x_scale, int r1_min, int r1_max, int y_scale, int r2_min, int r2_max, int bar_width, Color col, string label)
	:	origin(origin),
		data(data),
		x_scale(x_scale),
		r1_min(r1_min),
		r1_max(r1_max),
		y_scale(y_scale),
		r2_min(r2_min),
		r2_max(r2_max),
		bar_width(bar_width),
		col(col),
		label(label)
{

}

void bar_graph::draw_lines() const
{
	int ds = data.size();


	for (int i = 0; i < data.size(); i++) {

		double w = double(bar_width / 2);
		int h = data[i].height;
		int c = data[i].count;

		// scale factor
		double sx = (xlength / 2.0) / (r1_max - r1_min);
		double sy = (ylength / 2.0) / (r2_max - r2_min);
		
		Point p0(origin.x + (h - r1_min) * sx - w, origin.y - c * sy);
		Point p1(origin.x + (h - r1_min) * sx + w, origin.y);

		Graph_lib::Rectangle r(p0, p1);

		r.set_color(col);
		r.set_fill_color(col);

		r.draw();

		// bar labels
		string hl = to_string((int)data[i].height);
		Text height_label(Point(p1.x - bar_width, p1.y + 15), hl);
		height_label.set_color(col);
		height_label.draw();
		
		string cl = to_string((int)data[i].count);
		Text count_label(Point(p0.x, p0.y - 10), cl);
		count_label.set_color(col);
		count_label.draw();

	}

	// graph label
	Text gl(Point(origin.x - 70, origin.y + 15), label);
	gl.set_color(col);

	gl.draw();
}

int main()
try
{
	Point tl(100, 100);
	Simple_window win(tl, xmax, ymax, "Function graphs.");

	int r1_min = 160;
	int r1_max = 200;

	int r2_min = 5;
	int r2_max = 30;

	int bar_width = 15;
	
	// notch label x
	string x_notch = "1 == " + to_string((r1_max - r1_min) / 10);

	// notch label y
	ostringstream strs;
	strs << setprecision(2) << (r2_max - r2_min) / 10.0;
	string y_notch = "1 == " + strs.str();

	// x axis
	Axis x(Axis::x, Point(orig.x - 200, orig.y), 400, 20, x_notch);
	x.set_color(Color::black);
	win.attach(x);

	// y axis
	Axis y(Axis::y, Point(orig.x, orig.y + 200), 400, 20, y_notch);
	y.set_color(Color::black);
	win.attach(y);

	// people height data
	vector<ppl_height> d = {	ppl_height(170, 7),
								ppl_height(175, 9),
								ppl_height(180, 23),
								ppl_height(185, 17),
								ppl_height(190, 6),
								ppl_height(195, 1)
	};

	// stream data from file
	vector<ppl_height> dff;
	string location = "input/height_data.txt";
	read_data(location, dff);

	// bar graph
	bar_graph bg(orig, dff, x_scale, r1_min, r1_max, y_scale, r2_min, r2_max, bar_width, Color::blue, "bar graph");
	win.attach(bg);

	win.wait_for_button();
	keep_window_open();
}
catch (exception& e) {
	cerr << "error: " << e.what() << '\n';
	keep_window_open();
	return 1;
}

catch (...) {
	cerr << "Unknown exception!\n";
	keep_window_open();
	return 2;
}

elaborated bar graph class [fltk]

Bjarne Stroustrup “Programming Principles and Practice Using C++”
Chapter 15 Exercise 7
Using GUI library called FLTK (Fast Light Tool Kit, “full tick”).

Output:

//  Philipp Siedler
//  Bjarne Stroustrup's PP
//  Chapter 15 Exercise 7

#define _USE_MATH_DEFINES
#include "Simple_window.h"
#include "Graph.h"
#include <cmath>

ostream& operator<<(ostream& out, Point& a) {
	out << "(" << a.x << "," << a.y << ")";
	return out;
}

// layout
constexpr int xmax = 600;
constexpr int ymax = 600;

constexpr int x_orig = xmax / 2;
constexpr int y_orig = ymax / 2;
Point orig(x_orig, y_orig);

constexpr int r_min = -10;
constexpr int r_max = 10;

constexpr int n_points = 400;

constexpr int x_scale = 20;
constexpr int y_scale = 20;

constexpr int xoffset = 100;
constexpr int yoffset = 100;

constexpr int xspace = 100;
constexpr int yspace = 100;

constexpr int xlength = xmax - xoffset - xspace;
constexpr int ylength = ymax - yoffset - yspace;

// bar graph class

class bar_graph : public Shape
{
public:
	bar_graph(Point origin, vector<double> data, int bar_width, int gap_width, Color col, string label);

	void draw_lines() const;

	vector<double> get_data() { return data; }

private:
	Point origin;
	vector<double> data;

	int bar_width;
	int gap_width;

	Color col;

	string label;
};

bar_graph::bar_graph(Point origin, vector<double> data, int bar_width, int gap_width, Color col, string label)
	: origin(origin), data(data), bar_width(bar_width), gap_width(gap_width), col(col), label(label)
{

}

void bar_graph::draw_lines() const
{
	int ds = data.size();


	for (int i = 0; i < data.size(); i++) {
		Point p0(origin.x + i * (bar_width + gap_width), origin.y);
		Point p1(origin.x + i * (bar_width + gap_width) + bar_width, origin.y);
		Point p2(origin.x + i * (bar_width + gap_width) + bar_width, origin.y - data[i]);
		Point p3(origin.x + i * (bar_width + gap_width), origin.y - data[i]);

		Closed_polyline cp;
		cp.add(p0);
		cp.add(p1);
		cp.add(p2);
		cp.add(p3);

		cp.set_color(col);
		cp.set_fill_color(col);

		cp.draw();

		// bar label
		ostringstream strs;
		strs << data[i];
		string d = strs.str();

		Text bl(Point(p3.x, p3.y - 5), d);
		bl.set_color(col);

		bl.draw();

	}

	// graph label
	Text gl(Point(origin.x, origin.y + 15), label);
	gl.set_color(col);

	gl.draw();

}

int main()
try
{
	Point tl(100, 100);
	Simple_window win(tl, xmax, ymax, "Function graphs.");

	Axis x(Axis::x, Point(orig.x - 200, orig.y), 400, 20, "1 == 20");
	x.set_color(Color::black);
	win.attach(x);

	Axis y(Axis::y, Point(orig.x, orig.y + 200), 400, 20, "1 == 20");
	y.set_color(Color::black);
	win.attach(y);

	vector<double> d = { 120, 123, 115, 110, 55 };

	bar_graph bg(orig, d, 10, 20, Color::blue, "bar graph");

	win.attach(bg);

	win.wait_for_button();
	keep_window_open();
}
catch (exception& e) {
	cerr << "error: " << e.what() << '\n';
	keep_window_open();
	return 1;
}

catch (...) {
	cerr << "Unknown exception!\n";
	keep_window_open();
	return 2;
}

bar graph class [fltk]

Bjarne Stroustrup “Programming Principles and Practice Using C++”
Chapter 15 Exercise 6
Using GUI library called FLTK (Fast Light Tool Kit, “full tick”).

Output:

//  Philipp Siedler
//  Bjarne Stroustrup's PP
//  Chapter 15 Exercise 6

#define _USE_MATH_DEFINES
#include "Simple_window.h"
#include "Graph.h"
#include <cmath>

ostream& operator<<(ostream& out, Point& a) {
	out << "(" << a.x << "," << a.y << ")";
	return out;
}

// layout
constexpr int xmax = 600;
constexpr int ymax = 600;

constexpr int x_orig = xmax / 2;
constexpr int y_orig = ymax / 2;
Point orig(x_orig, y_orig);

constexpr int r_min = -10;
constexpr int r_max = 10;

constexpr int n_points = 400;

constexpr int x_scale = 20;
constexpr int y_scale = 20;

constexpr int xoffset = 100;
constexpr int yoffset = 100;

constexpr int xspace = 100;
constexpr int yspace = 100;

constexpr int xlength = xmax - xoffset - xspace;
constexpr int ylength = ymax - yoffset - yspace;

// bar graph class

class bar_graph : public Shape
{
public:
	bar_graph(Point origin, vector<double> data, int bar_width, int gap_width, Color col);
		
	void draw_lines() const;

	vector<double> get_data() { return data; }

private:
	Point origin;
	vector<double> data;

	int bar_width;
	int gap_width;

	Color col;
};

bar_graph::bar_graph(Point origin, vector<double> data, int bar_width, int gap_width, Color col)
	: origin(origin), data(data), bar_width(bar_width), gap_width(gap_width), col(col)
{

}

void bar_graph::draw_lines() const
{
	int ds = data.size();

	
	for (int i = 0; i < data.size(); i++) {
		Point p0(origin.x + i * (bar_width + gap_width), origin.y);
		Point p1(origin.x + i * (bar_width + gap_width) + bar_width, origin.y);
		Point p2(origin.x + i * (bar_width + gap_width) + bar_width, origin.y - data[i]);
		Point p3(origin.x + i * (bar_width + gap_width), origin.y - data[i]);

		Closed_polyline cp;
		cp.add(p0);
		cp.add(p1);
		cp.add(p2);
		cp.add(p3);
		
		cp.set_color(col);
		cp.set_fill_color(col);

		cp.draw();
	}
	
}

int main()
try
{
	Point tl(100, 100);
	Simple_window win(tl, xmax, ymax, "Function graphs.");

	Axis x(Axis::x, Point(orig.x - 200, orig.y), 400, 20, "1 == 20");
	x.set_color(Color::black);
	win.attach(x);

	Axis y(Axis::y, Point(orig.x, orig.y + 200), 400, 20, "1 == 20");
	y.set_color(Color::black);
	win.attach(y);

	vector<double> d = { 120, 123, 115, 110, 55};
	
	bar_graph bg(orig, d, 10, 20, Color::red);

	win.attach(bg);

	win.wait_for_button();
	keep_window_open();
}
catch (exception& e) {
	cerr << "error: " << e.what() << '\n';
	keep_window_open();
	return 1;
}

catch (...) {
	cerr << "Unknown exception!\n";
	keep_window_open();
	return 2;
}