Page 1 of 1

C++ FLTK (X,Y) AXIS TUTORIAL - Part 1 C++ FLTK (X,Y) AXIS TUTORIAL - Part 1 Rate Topic: -----

#1 Elcric  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 101
  • View blog
  • Posts: 453
  • Joined: 02-May 09

Posted 31 August 2009 - 12:05 PM

C++ FLTK (X,Y) AXIS TUTORIAL PART 1



WHAT YOU WILL LEARN IN THIS TUTORIAL:

You will learn about Bjarne Stroustrup: “Programming Principles and Practices Using C++” Addison-Wesley 2009, ISBN 978-0321543721.

• I. INTRODUCTION

Hello; nice to meet you! Welcome to the “C++ FLTK (X,Y) Axis Tutorial - Part 1.”

This tutorial is a very brief overview of information presented by Dr. Bjarne Stroustrup in his book “Programming Principles and Practices Using C++,” Addison-Wesley 2009, ISBN 978-0321543721.

The web site is:

http://www.stroustrup.com/Programming/

• II. HEADER FILES

You will need the following header files to run the tutorial:

Graph.h

// This is a GUI support code to the chapters 12-16 of the book
// "Programming -- Principles and Practice Using C++" by Bjarne Stroustrup
//

#ifndef GRAPH_GUARD
#define GRAPH_GUARD 1

#include <FL/fl_draw.H>
#include <FL/Fl_Image.H>
#include "Point.h"
#include "std_lib_facilities.h"

namespace Graph_lib {

// defense against ill-behaved Linux macros:
#undef major
#undef minor

//------------------------------------------------------------------------------

// Color is the type we use to represent color. We can use Color like this:
//	grid.set_color(Color::red);
struct Color {
	enum Color_type {
		red=FL_RED,
		blue=FL_BLUE,
		green=FL_GREEN,
		yellow=FL_YELLOW,
		white=FL_WHITE,
		black=FL_BLACK,
		magenta=FL_MAGENTA,
		cyan=FL_CYAN,
		dark_red=FL_DARK_RED,
		dark_green=FL_DARK_GREEN,
		dark_yellow=FL_DARK_YELLOW,
		dark_blue=FL_DARK_BLUE,
		dark_magenta=FL_DARK_MAGENTA,
		dark_cyan=FL_DARK_CYAN
	};

	enum Transparency { invisible = 0, visible=255 };

	Color(Color_type cc) :c(Fl_Color(cc)), v(visible) { }
	Color(Color_type cc, Transparency vv) :c(Fl_Color(cc)), v(vv) { }
	Color(int cc) :c(Fl_Color(cc)), v(visible) { }
	Color(Transparency vv) :c(Fl_Color()), v(vv) { }	// default color

	int as_int() const { return c; }

	char visibility() const { return v; } 
	void set_visibility(Transparency vv) { v=vv; }
private:
	char v;	// invisible and visible for now
	Fl_Color c;
};

//------------------------------------------------------------------------------

struct Line_style {
	enum Line_style_type {
		solid=FL_SOLID,			// -------
		dash=FL_DASH,			  // - - - -
		dot=FL_DOT,				// ....... 
		dashdot=FL_DASHDOT,		// - . - . 
		dashdotdot=FL_DASHDOTDOT,  // -..-..
	};

	Line_style(Line_style_type ss) :s(ss), w(0) { }
	Line_style(Line_style_type lst, int ww) :s(lst), w(ww) { }
	Line_style(int ss) :s(ss), w(0) { }

	int width() const { return w; }
	int style() const { return s; }
private:
	int s;
	int w;
};

//------------------------------------------------------------------------------

class Font {
public:
	enum Font_type {
		helvetica=FL_HELVETICA,
		helvetica_bold=FL_HELVETICA_BOLD,
		helvetica_italic=FL_HELVETICA_ITALIC,
		helvetica_bold_italic=FL_HELVETICA_BOLD_ITALIC,
		courier=FL_COURIER,
		courier_bold=FL_COURIER_BOLD,
		courier_italic=FL_COURIER_ITALIC,
		courier_bold_italic=FL_COURIER_BOLD_ITALIC,
		times=FL_TIMES,
		times_bold=FL_TIMES_BOLD,
		times_italic=FL_TIMES_ITALIC,
		times_bold_italic=FL_TIMES_BOLD_ITALIC,
		symbol=FL_SYMBOL,
		screen=FL_SCREEN,
		screen_bold=FL_SCREEN_BOLD,
		zapf_dingbats=FL_ZAPF_DINGBATS
	};

	Font(Font_type ff) :f(ff) { }
	Font(int ff) :f(ff) { }

	int as_int() const { return f; }
private:
	int f;
};

//------------------------------------------------------------------------------

template<class T> class Vector_ref {
	vector<T*> v;
	vector<T*> owned;
public:
	Vector_ref() {}
	Vector_ref(T& a) { push_back(a); }
	Vector_ref(T& a, T& b);
	Vector_ref(T& a, T& b, T& c);
	Vector_ref(T* a, T* b = 0, T* c = 0, T* d = 0)
	{
		if (a) push_back(a);
		if (b) push_back(b);
		if (c) push_back(c);
		if (d) push_back(d);
	}

	~Vector_ref() { for (int i=0; i<owned.size(); ++i) delete owned[i]; }

	void push_back(T& s) { v.push_back(&s); }
	void push_back(T* p) { v.push_back(p); owned.push_back(p); }

	T& operator[](int i) { return *v[i]; }
	const T& operator[](int i) const { return *v[i]; }

	int size() const { return v.size(); }
};

//------------------------------------------------------------------------------

typedef double Fct(double);

class Shape  {		// deals with color and style, and holds sequence of lines 
public:
	void draw() const;				 // deal with color and draw lines
	virtual void move(int dx, int dy); // move the shape +=dx and +=dy

	void set_color(Color col) { lcolor = col; }
	Color color() const { return lcolor; }
	void set_style(Line_style sty) { ls = sty; }
	Line_style style() const { return ls; }
	void set_fill_color(Color col) { fcolor = col; }
	Color fill_color() const { return fcolor; }

	Point point(int i) const { return points[i]; } // read only access to points
	int number_of_points() const { return int(points.size()); }

	virtual ~Shape() { }
protected:
	Shape();	
	virtual void draw_lines() const;   // draw the appropriate lines
	void add(Point p);				 // add p to points
	void set_point(int i,Point p);	 // points[i]=p;
private:
	vector<Point> points;			  // not used by all shapes
	Color lcolor;					  // color for lines and characters
	Line_style ls; 
	Color fcolor;					  // fill color

	Shape(const Shape&);			   // prevent copying
	Shape& operator=(const Shape&);
};

//------------------------------------------------------------------------------

struct Function : Shape {
	// the function parameters are not stored
	Function(Fct f, double r1, double r2, Point orig,
		int count = 100, double xscale = 25, double yscale = 25);	
};

//------------------------------------------------------------------------------

struct Line : Shape {			// a Line is a Shape defined by two Points
	Line(Point p1, Point p2);	// construct a line from two points
};

//------------------------------------------------------------------------------

struct Rectangle : Shape {

	Rectangle(Point xy, int ww, int hh) : w(ww), h(hh)
	{
		add(xy);
		if (h<=0 || w<=0) error("Bad rectangle: non-positive side");
	}

	Rectangle(Point x, Point y) : w(y.x-x.x), h(y.y-x.y)
	{
		add(x);
		if (h<=0 || w<=0) error("Bad rectangle: non-positive width or height");
	}
	void draw_lines() const;

	int height() const { return h; }
	int width() const { return w; }
private:
	int h;	// height
	int w;	// width
};

//------------------------------------------------------------------------------

struct Open_polyline : Shape {		 // open sequence of lines
	void add(Point p) { Shape::add(p); }
	void draw_lines() const;
};

//------------------------------------------------------------------------------

struct Closed_polyline : Open_polyline { // closed sequence of lines
	void draw_lines() const;
};

//------------------------------------------------------------------------------

struct Polygon : Closed_polyline {	// closed sequence of non-intersecting lines
	void add(Point p);
	void draw_lines() const;
};

//------------------------------------------------------------------------------

struct Lines : Shape {				 // related lines
	void draw_lines() const;
	void add(Point p1, Point p2);	  // add a line defined by two points
};

//------------------------------------------------------------------------------

struct Text : Shape {
	// the point is the bottom left of the first letter
	Text(Point x, const string& s) : lab(s), fnt(fl_font()), fnt_sz(fl_size()) { add(x); }

	void draw_lines() const;

	void set_label(const string& s) { lab = s; }
	string label() const { return lab; }

	void set_font(Font f) { fnt = f; }
	Font font() const { return Font(fnt); }

	void set_font_size(int s) { fnt_sz = s; }
	int font_size() const { return fnt_sz; }
private:
	string lab;	// label
	Font fnt;
	int fnt_sz;
};

//------------------------------------------------------------------------------

struct Axis : Shape {
	enum Orientation { x, y, z };
	Axis(Orientation d, Point xy, int length,
		int number_of_notches=0, string label = "");

	void draw_lines() const;
	void move(int dx, int dy);
	void set_color(Color c);

	Text label;
	Lines notches;
};

//------------------------------------------------------------------------------

struct Circle : Shape {
	Circle(Point p, int rr);	// center and radius

	void draw_lines() const;

	Point center() const; 
	int radius() const { return r; }
	void set_radius(int rr) { r=rr; }
private:
	int r;
};

//------------------------------------------------------------------------------

struct Ellipse : Shape {
	Ellipse(Point p, int w, int h)	// center, min, and max distance from center
		: w(w), h(h)
	{ 
		add(Point(p.x-w,p.y-h));
	}

	void draw_lines() const;

	Point center() const { return Point(point(0).x+w,point(0).y+h); }
	Point focus1() const { return Point(center().x+int(sqrt(double(w*w-h*h))),center().y); }
	Point focus2() const { return Point(center().x-int(sqrt(double(w*w-h*h))),center().y); }

	void set_major(int ww) { w=ww; }
	int major() const { return w; }
	void set_minor(int hh) { h=hh; }
	int minor() const { return h; }
private:
	int w;
	int h;
};

//------------------------------------------------------------------------------

struct Marked_polyline : Open_polyline {
	Marked_polyline(const string& m) :mark(m) { }
	void draw_lines() const;
private:
	string mark;
};

//------------------------------------------------------------------------------

struct Marks : Marked_polyline {
	Marks(const string& m) :Marked_polyline(m)
	{
		set_color(Color(Color::invisible));
	}
};

//------------------------------------------------------------------------------

struct Mark : Marks {
	Mark(Point xy, char c) : Marks(string(1,c))
	{
		add(xy);
	}
};

//------------------------------------------------------------------------------

struct Suffix {
	enum Encoding { none, jpg, gif  };
};

Suffix::Encoding get_encoding(const string& s);

//------------------------------------------------------------------------------

struct Image : Shape {
	Image(Point xy, string file_name, Suffix::Encoding e = Suffix::none);
	~Image() { delete p; }
	void draw_lines() const;
	void set_mask(Point xy, int ww, int hh) { w=ww; h=hh; cx=xy.x; cy=xy.y; }
private:
	int w,h;  // define "masking box" within image relative to position (cx,cy)
	int cx,cy; 
	Fl_Image* p;
	Text fn;
};

//------------------------------------------------------------------------------

struct Bad_image : Fl_Image {
	Bad_image(int h, int w) : Fl_Image(h,w,0) { }
	void draw(int x,int y, int, int, int, int) { draw_empty(x,y); }
};

//------------------------------------------------------------------------------

} // of namespace Graph_lib

#endif



GUI.h
//
// This is a GUI support code to the chapters 12-16 of the book
// "Programming -- Principles and Practice Using C++" by Bjarne Stroustrup
//

#ifndef GUI_GUARD
#define GUI_GUARD

#include "window.h"
#include "Graph.h"

namespace Graph_lib {

//------------------------------------------------------------------------------

	typedef void* Address;	// Address is a synonym for void*
	typedef void(*Callback)(Address, Address);	// FLTK's required function type for all callbacks

//------------------------------------------------------------------------------

	template<class W> W& reference_to(Address pw)
	// treat an address as a reference to a W
	{
		return *static_cast<W*>(pw);
	}

//------------------------------------------------------------------------------

	class Widget {
	// Widget is a handle to an Fl_widget - it is *not* an Fl_widget
	// We try to keep our interface classes at arm's length from FLTK
	public:
		Widget(Point xy, int w, int h, const string& s, Callback cb)
			: loc(xy), width(w), height(h), label(s), do_it(cb)
		{}

		virtual void move(int dx,int dy) { hide(); pw->position(loc.x+=dx, loc.y+=dy); show(); }
		virtual void hide() { pw->hide(); }
		virtual void show() { pw->show(); }
		virtual void attach(Window&) = 0;

		Point loc;
		int width;
		int height;
		string label;
		Callback do_it;

		virtual ~Widget() { }

	protected:
		Window* own;	// every Widget belongs to a Window
		Fl_Widget* pw;  // connection to the FLTK Widget
	private:
		Widget& operator=(const Widget&); // don't copy Widgets
		Widget(const Widget&);
	};

//------------------------------------------------------------------------------

	struct Button : Widget {
		Button(Point xy, int w, int h, const string& label, Callback cb)
			: Widget(xy,w,h,label,cb)
		{}

		void attach(Window&);
	};

//------------------------------------------------------------------------------

	struct In_box : Widget {
		In_box(Point xy, int w, int h, const string& s)
			:Widget(xy,w,h,s,0) { }
		int get_int();
		string get_string();

		void attach(Window& win);
	};

//------------------------------------------------------------------------------

	struct Out_box : Widget {
		Out_box(Point xy, int w, int h, const string& s)
			:Widget(xy,w,h,s,0) { }
		void put(int);
		void put(const string&);

		void attach(Window& win);
	};

//------------------------------------------------------------------------------

	struct Menu : Widget {
		enum Kind { horizontal, vertical };
		Menu(Point xy, int w, int h, Kind kk, const string& label)
			: Widget(xy,w,h,label,0), k(kk), offset(0)
		{}

		Vector_ref<Button> selection;
		Kind k;
		int offset;
		int attach(Button& b);	  // Menu does not delete &b
		int attach(Button* p);	  // Menu deletes p

		void show()				 // show all buttons
		{
			for (unsigned int i = 0; i<selection.size(); ++i)
				selection[i].show();
		}
		void hide()				 // hide all buttons
		{
			for (unsigned int i = 0; i<selection.size(); ++i) 
				selection[i].hide(); 
		}
		void move(int dx, int dy)   // move all buttons
		{
			for (unsigned int i = 0; i<selection.size(); ++i) 
				selection[i].move(dx,dy);
		}

		void attach(Window& win)	// attach all buttons
		{
			for (int i=0; i<selection.size(); ++i) win.attach(selection[i]);
			own = &win;
		}

	};

//------------------------------------------------------------------------------

} // of namespace Graph_lib

#endif // GUI_GUARD



Point.h

//
// This is a GUI support code to the chapters 12-16 of the book
// "Programming -- Principles and Practice Using C++" by Bjarne Stroustrup
//

#ifndef POINT_GUARD
#define POINT_GUARD

//------------------------------------------------------------------------------

struct Point {
	int x, y;
	Point(int xx, int yy) : x(xx), y(yy) { }
	Point() :x(0), y(0) { }
};

//------------------------------------------------------------------------------

inline bool operator==(Point a, Point b) { return a.x==b.x && a.y==b.y; } 

//------------------------------------------------------------------------------

inline bool operator!=(Point a, Point b) { return !(a==b); }

//------------------------------------------------------------------------------

#endif // POINT_GUARD



Simple_window.h

//
// This is a GUI support code to the chapters 12-16 of the book
// "Programming -- Principles and Practice Using C++" by Bjarne Stroustrup
//

#ifndef SIMPLE_WINDOW_GUARD
#define SIMPLE_WINDOW_GUARD 1

#include "GUI.h"	// for Simple_window only (doesn't really belong in window.h)
#include "Graph.h"

using namespace Graph_lib;

//------------------------------------------------------------------------------

struct Simple_window : Window {
	Simple_window(Point xy, int w, int h, const string& title );

	bool wait_for_button(); // simple event loop

private:
	Button next_button;	 // the "next" button
	bool button_pushed;	 // implementation detail

	static void cb_next(Address, Address); // callback for next_button
	void next();			// action to be done when next_button is pressed

};

//------------------------------------------------------------------------------

#endif // SIMPLE_WINDOW_GUARD



Std_library_facilities.h

//
// This is a standard library support code to the chapters of the book
// "Programming -- Principles and Practice Using C++" by Bjarne Stroustrup
//

#ifndef STD_LIB_FACILITIES_GUARD
#define STD_LIB_FACILITIES_GUARD 1

#include <cmath>
#include <cstring>
#include <fstream>
#include <stdexcept>
#include <string>
#include <sstream>
#include <vector>

using namespace std;

//------------------------------------------------------------------------------

// Helper function to show an error message
inline void error(const string& errormessage)
{
	throw runtime_error(errormessage);
}

//------------------------------------------------------------------------------

inline void error(string s1, string s2)
{
	error(s1+s2);
}

//------------------------------------------------------------------------------

#endif // STD_LIB_FACILITIES_GUARD



window.h

//
// This is a GUI support code to the chapters 12-16 of the book
// "Programming -- Principles and Practice Using C++" by Bjarne Stroustrup
//

#ifndef WINDOW_GUARD
#define WINDOW_GUARD

#include <string>
#include <vector>
#include <FL/Fl.H>
#include <FL/Fl_window.H>
#include "Point.h"

using std::string;
using std::vector;

namespace Graph_lib
{
	class Shape;   // "forward declare" Shape
	class Widget;

//------------------------------------------------------------------------------

	class Window : public Fl_Window { 
	public:
		// let the system pick the location:
		Window(int w, int h, const string& title);
		// top left corner in xy
		Window(Point xy, int w, int h, const string& title);	

		virtual ~Window() { }

		int x_max() const { return w; }
		int y_max() const { return h; }

		void resize(int ww, int hh) { w=ww, h=hh; size(ww,hh); }

		void set_label(const string& s) { copy_label(s.c_str()); }

		void attach(Shape& s) { shapes.push_back(&s); }
		void attach(Widget&);

		void detach(Shape& s);	 // remove s from shapes 
		void detach(Widget& w);	// remove w from window (deactivates callbacks)

		void put_on_top(Shape& p); // put p on top of other shapes

	protected:
		void draw();

	private:
		vector<Shape*> shapes;	 // shapes attached to window
		int w,h;				   // window size

		void init();
	};

//------------------------------------------------------------------------------

		   int gui_main(); // invoke GUI library's main event loop
	inline int x_max() { return Fl::w(); } // width of screen in pixels
	inline int y_max() { return Fl::h(); } // height of screen in pixels

} // of namespace Graph_lib

#endif // WINDOW_GUARD



• III. .CPP FILES

You will need the following .cpp files to run the tutorial:

Graph.cpp

//
// This is a GUI support code to the chapters 12-16 of the book
// "Programming -- Principles and Practice Using C++" by Bjarne Stroustrup
//

#include <FL/Fl_GIF_Image.H>
#include <FL/Fl_JPEG_Image.H>
#include "Graph.h"
#include <cstdlib>
#include <cstring>

//------------------------------------------------------------------------------

namespace Graph_lib {

//------------------------------------------------------------------------------

Shape::Shape() : 
	lcolor(fl_color()),	  // default color for lines and characters
	ls(0),				   // default style
	fcolor(Color::invisible) // no fill
{}

//------------------------------------------------------------------------------

void Shape::add(Point p)	 // protected
{
	points.push_back(p);
}

//------------------------------------------------------------------------------

void Shape::set_point(int i,Point p)		// not used; not necessary so far
{
	points[i] = p;
}

//------------------------------------------------------------------------------

void Shape::draw_lines() const
{
	if (color().visibility() && 1<points.size())	// draw sole pixel?
		for (unsigned int i=1; i<points.size(); ++i)
			fl_line(points[i-1].x,points[i-1].y,points[i].x,points[i].y);
}

//------------------------------------------------------------------------------

void Shape::draw() const
{
	Fl_Color oldc = fl_color();
	// there is no good portable way of retrieving the current style
	fl_color(lcolor.as_int());			// set color
	fl_line_style(ls.style(),ls.width()); // set style
	draw_lines();
	fl_color(oldc);	  // reset color (to previous)
	fl_line_style(0);	// reset line style to default
}

//------------------------------------------------------------------------------


void Shape::move(int dx, int dy)	// move the shape +=dx and +=dy
{
	for (int i = 0; i<points.size(); ++i) {
		points[i].x+=dx;
		points[i].y+=dy;
	}
}

//------------------------------------------------------------------------------

Line::Line(Point p1, Point p2)	// construct a line from two points
{
	add(p1);	// add p1 to this shape
	add(p2);	// add p2 to this shape
}

//------------------------------------------------------------------------------

void Lines::add(Point p1, Point p2)
{
	Shape::add(p1);
	Shape::add(p2);
}

//------------------------------------------------------------------------------

// draw lines connecting pairs of points
void Lines::draw_lines() const
{
	if (color().visibility())
		for (int i=1; i<number_of_points(); i+=2)
			fl_line(point(i-1).x,point(i-1).y,point(i).x,point(i).y);
}

//------------------------------------------------------------------------------

// does two lines (p1,p2) and (p3,p4) intersect?
// if se return the distance of the intersect point as distances from p1
inline pair<double,double> line_intersect(Point p1, Point p2, Point p3, Point p4, bool& parallel) 
{
	double x1 = p1.x;
	double x2 = p2.x;
	double x3 = p3.x;
	double x4 = p4.x;
	double y1 = p1.y;
	double y2 = p2.y;
	double y3 = p3.y;
	double y4 = p4.y;

	double denom = ((y4 - y3)*(x2-x1) - (x4-x3)*(y2-y1));
	if (denom == 0){
		parallel= true;
		return pair<double,double>(0,0);
	}
	parallel = false;
	return pair<double,double>( ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3))/denom,
								((x2-x1)*(y1-y3) - (y2-y1)*(x1-x3))/denom);
}

//------------------------------------------------------------------------------

//intersection between two line segments
//Returns true if the two segments intersect,
//in which case intersection is set to the point of intersection
bool line_segment_intersect(Point p1, Point p2, Point p3, Point p4, Point& intersection){
   bool parallel;
   pair<double,double> u = line_intersect(p1,p2,p3,p4,parallel);
   if (parallel || u.first < 0 || u.first > 1 || u.second < 0 || u.second > 1) return false;
   intersection.x = p1.x + u.first*(p2.x - p1.x);
   intersection.y = p1.y + u.first*(p2.y - p1.y);
   return true;
}

//------------------------------------------------------------------------------

void Polygon::add(Point p)
{
	int np = number_of_points();

	if (1<np) {	// check that thenew line isn't parallel to the previous one
		if (p==point(np-1)) error("polygon point equal to previous point");
		bool parallel;
		line_intersect(point(np-1),p,point(np-2),point(np-1),parallel);
		if (parallel)
			error("two polygon points lie in a straight line");
	}

	for (int i = 1; i<np-1; ++i) {	// check that new segment doesn't interset and old point
		Point ignore(0,0);
		if (line_segment_intersect(point(np-1),p,point(i-1),point(i),ignore))
			error("intersect in polygon");
	}
	

	Closed_polyline::add(p);
}

//------------------------------------------------------------------------------

void Polygon::draw_lines() const
{
	if (number_of_points() < 3) error("less than 3 points in a Polygon");
	Closed_polyline::draw_lines();
}

//------------------------------------------------------------------------------

void Open_polyline::draw_lines() const
{
	if (fill_color().visibility()) {
		fl_color(fill_color().as_int());
		fl_begin_complex_polygon();
		for(int i=0; i<number_of_points(); ++i){
			fl_vertex(point(i).x, point(i).y);
		}
		fl_end_complex_polygon();
		fl_color(color().as_int());	// reset color
	}
	
	if (color().visibility())
		Shape::draw_lines();
}

//------------------------------------------------------------------------------

void Closed_polyline::draw_lines() const
{
	Open_polyline::draw_lines();	// first draw the "open poly line part"
	// then draw closing line:
	if (color().visibility())
		fl_line(point(number_of_points()-1).x, 
		point(number_of_points()-1).y,
		point(0).x,
		point(0).y);
}

//------------------------------------------------------------------------------

void draw_mark(Point xy, char c)
{
	static const int dx = 4;
	static const int dy = 4;

	string m(1,c);
	fl_draw(m.c_str(),xy.x-dx,xy.y+dy);
}

//------------------------------------------------------------------------------

void Marked_polyline::draw_lines() const
{
	Open_polyline::draw_lines();
	for (int i=0; i<number_of_points(); ++i) 
		draw_mark(point(i),mark[i%mark.size()]);
}

//------------------------------------------------------------------------------

void Rectangle::draw_lines() const
{
	if (fill_color().visibility()) {	// fill
		fl_color(fill_color().as_int());
		fl_rectf(point(0).x,point(0).y,w,h);
	}

	if (color().visibility()) {	// lines on top of fill
		fl_color(color().as_int());
		fl_rect(point(0).x,point(0).y,w,h);
	}
}

//------------------------------------------------------------------------------

Circle::Circle(Point p, int rr)	// center and radius
:r(rr)
{
	add(Point(p.x-r,p.y-r));	   // store top-left corner
}

//------------------------------------------------------------------------------

Point Circle::center() const
{
	return Point(point(0).x+r, point(0).y+r);
}

//------------------------------------------------------------------------------

void Circle::draw_lines() const
{
	if (color().visibility())
		fl_arc(point(0).x,point(0).y,r+r,r+r,0,360);
}

//------------------------------------------------------------------------------

void Ellipse::draw_lines() const
{
	if (color().visibility())
		fl_arc(point(0).x,point(0).y,w+w,h+h,0,360);
}

//------------------------------------------------------------------------------

void Text::draw_lines() const
{
	int ofnt = fl_font();
	int osz = fl_size();
	fl_font(fnt.as_int(),fnt_sz);
	fl_draw(lab.c_str(),point(0).x,point(0).y);
	fl_font(ofnt,osz);
}

//------------------------------------------------------------------------------

Axis::Axis(Orientation d, Point xy, int length, int n, string lab) :
	label(Point(0,0),lab)
{
	if (length<0) error("bad axis length");
	switch (d){
	case Axis::x:
	{
		Shape::add(xy); // axis line
		Shape::add(Point(xy.x+length,xy.y));

		if (1<n) {	  // add notches
			int dist = length/n;
			int x = xy.x+dist;
			for (int i = 0; i<n; ++i) {
				notches.add(Point(x,xy.y),Point(x,xy.y-5));
				x += dist;
			}
		}
		// label under the line
		label.move(length/3,xy.y+20);
		break;
	}
	case Axis::y:
	{
		Shape::add(xy); // a y-axis goes up
		Shape::add(Point(xy.x,xy.y-length));

		if (1<n) {	  // add notches
			int dist = length/n;
			int y = xy.y-dist;
			for (int i = 0; i<n; ++i) {
				notches.add(Point(xy.x,y),Point(xy.x+5,y));
				y -= dist;
			}
		}
		// label at top
		label.move(xy.x-10,xy.y-length-10);
		break;
	}
	case Axis::z:
		error("z axis not implemented");
	}
}

//------------------------------------------------------------------------------

void Axis::draw_lines() const
{
	Shape::draw_lines();
	notches.draw();  // the notches may have a different color from the line
	label.draw();	// the label may have a different color from the line
}

//------------------------------------------------------------------------------

void Axis::set_color(Color c)
{
	Shape::set_color(c);
	notches.set_color(c);
	label.set_color(c);
}

//------------------------------------------------------------------------------

void Axis::move(int dx, int dy)
{
	Shape::move(dx,dy);
	notches.move(dx,dy);
	label.move(dx,dy);
}

//------------------------------------------------------------------------------

Function::Function(Fct f, double r1, double r2, Point xy,
				   int count, double xscale, double yscale)
// graph f(x) for x in [r1:r2) using count line segments with (0,0) displayed at xy
// x coordinates are scaled by xscale and y coordinates scaled by yscale
{
	if (r2-r1<=0) error("bad graphing range");
	if (count <=0) error("non-positive graphing count");
	double dist = (r2-r1)/count;
	double r = r1;
	for (int i = 0; i<count; ++i) {
		add(Point(xy.x+int(r*xscale),xy.y-int(f(r)*yscale)));
		r += dist;
	}
}

//------------------------------------------------------------------------------

bool can_open(const string& s)
// check if a file named s exists and can be opened for reading
{
	ifstream ff(s.c_str());
	return ff;
}

//------------------------------------------------------------------------------

#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))

Suffix::Encoding get_encoding(const string& s)
{
	struct SuffixMap 
	{ 
		const char*	  extension;
		Suffix::Encoding suffix;
	};

	static SuffixMap smap[] = {
		{".jpg",  Suffix::jpg},
		{".jpeg", Suffix::jpg},
		{".gif",  Suffix::gif},
	};

	for (int i = 0, n = ARRAY_SIZE(smap); i < n; i++)
	{
		int len = strlen(smap[i].extension);

		if (s.length() >= len && s.substr(s.length()-len, len) == smap[i].extension)
			return smap[i].suffix;
	}

	return Suffix::none;
}

//------------------------------------------------------------------------------

// somewhat over-elaborate constructor
// because errors related to image files can be such a pain to debug
Image::Image(Point xy, string s, Suffix::Encoding e)
	:w(0), h(0), fn(xy,"")
{
	add(xy);

	if (!can_open(s)) {	// can we open s?
		fn.set_label("cannot open \""+s+'\"');
		p = new Bad_image(30,20);	// the "error image"
		return;
	}

	if (e == Suffix::none) e = get_encoding(s);

	switch(e) {		// check if it is a known encoding
	case Suffix::jpg:
		p = new Fl_JPEG_Image(s.c_str());
		break;
	case Suffix::gif:
		p = new Fl_GIF_Image(s.c_str());
		break;
	default:	// Unsupported image encoding
		fn.set_label("unsupported file type \""+s+'\"');
		p = new Bad_image(30,20);	// the "error image"
	}
}

//------------------------------------------------------------------------------

void Image::draw_lines() const
{
	if (fn.label()!="") fn.draw_lines();

	if (w&&h)
		p->draw(point(0).x,point(0).y,w,h,cx,cy);
	else
		p->draw(point(0).x,point(0).y);
}

//------------------------------------------------------------------------------

} // of namespace Graph_lib



GUI.cpp

[code]
//
// This is a GUI support code to the chapters 12-16 of the book
// "Programming -- Principles and Practice Using C++" by Bjarne Stroustrup
//

#include <FL/Fl.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Output.H>
#include "GUI.h"
#include <cstdlib>
#include <cstring>

namespace Graph_lib {

//------------------------------------------------------------------------------

void Button::attach(Window

Is This A Good Question/Topic? 1
  • +

Page 1 of 1