Bjarne Stroustrup “Programming Principles and Practice Using C++”
Chapter 16 Exercise 10
Using GUI library called FLTK (Fast Light Tool Kit, “full tick”).
Output:![]()
// Philipp Siedler // Bjarne Stroustrup's PP // Chapter 16 Exercise 10 #define _USE_MATH_DEFINES #include "Simple_window.h" #include "Graph.h" #include <cmath> #include "GUI.h" #include "std_lib_facilities.h" #include <functional> // 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 = 40; constexpr int x_scale = 20; constexpr int y_scale = 20; // layout 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; typedef double Fcti(double); double mysin(double x) { return sin(x); } double mycos(double x) { return cos(x); } template <class T> class myFct : public Shape { public: myFct(Fcti* f, double r1, double r2, Point orig, int count = 100, double xscale = 25, double yscale = 25, T precision = 1.0); ~myFct() {} void set_f(Fcti* p) { f = p; } void set_r1(double r) { r1 = r; } void set_r2(double r) { r2 = r; } void set_orig(Point o) { orig = o; } void set_count(int c) { count = c; } void set_xscale(double x) { xscale = x; } void set_yscale(double y) { yscale = y; } void set_precision(T p) { precision = p; } double get_r1() { return r1; } double get_r2() { return r2; } Point get_orig() { return orig; } int get_count() { return count; } double get_xscale() { return xscale; } double get_yscale() { return yscale; } T get_precision() { return precision; } void calc(); void reset(Fcti* f, double r1, double r2, Point orig, int count = 100, double xscale = 25, double yscale = 25, T precision = 1.0); private: Fcti* f; double r1; double r2; Point orig; int count; double xscale; double yscale; T precision; }; template <class T> myFct<T>::myFct(Fcti* f, double r1, double r2, Point orig, int count, double xscale, double yscale, T precision) :f(f), r1(r1), r2(r2), orig(orig), count(count), xscale(xscale), yscale(yscale), precision(precision) { calc(); } template <class T> void myFct<T>::calc() { if (r2 - r1 <= 0) error("bad graphing range"); if (count <= 0) error("non-positive graphing count"); double dist = (r2 - r1) / count; double r = r1; // had to add void clear_points() { points.clear(); } // to the protected section of the Shape class - annoying clear_points(); for (int i = 0; i < count; ++i) { int x = orig.x + int(int(r * xscale) / precision) * precision; int y = orig.y - int(int(f(r) * yscale) / precision) * precision; add(Point(x, y)); r += dist; } } template <class T> void myFct<T>::reset(Fcti* f, double r1, double r2, Point orig, int count, double xscale, double yscale, T precision) { set_f(f); set_r1(r1); set_r2(r2); set_orig(orig); set_count(count); set_xscale(xscale); set_yscale(yscale); set_precision(precision); calc(); } // ------------------------------ GRAPHING END------------------------- struct application_window : Window { enum graph_enum { sin_g, cos_g }; application_window(Point xy, int w, int h, const string& title); void draw_graph(); private: //------------- LAYOUT // quit button Button quit_button; // convert button Button graph_button; // graph type button; Button graph_type; Menu graph_type_menu; // in In_box x_parameter; Out_box base_equation; Out_box equation; // graph_enum g_type; // axis Axis x_axis; Axis y_axis; // function myFct<double> funct; //double x_manipulation(double x, int m) { return x * m; } double my_sin(double x) { return sin(x); } double my_cos(double x) { return cos(x); } // actions invoked by callbacks void quit() { hide(); } void graph_type_menu_pressed() { graph_type.hide(); graph_type_menu.show(); } void sin_graph(); void cos_graph(); // callback functions static void cb_quit(Address, Address pw) { reference_to<application_window>(pw).quit(); } static void cb_calculate(Address, Address pw) { reference_to<application_window>(pw).draw_graph(); } static void cb_graph_type_menu_pressed(Address, Address pw) { reference_to<application_window>(pw).graph_type_menu_pressed(); } static void cb_sin_graph(Address, Address pw) { reference_to<application_window>(pw).sin_graph(); } static void cb_cos_graph(Address, Address pw) { reference_to<application_window>(pw).cos_graph(); } //------------- LAYOUT END }; application_window::application_window(Point xy, int w, int h, const string& title) : Window(xy, w, h, title) , quit_button(Point(x_max() - 70, 0), 70, 20, "Quit", cb_quit) , graph_button(Point(x_max() - 70, 20), 70, 20, "Graph", cb_calculate) , graph_type(Point(20, 0), 100, 20, "Graph Type", cb_graph_type_menu_pressed) , graph_type_menu(Point(20, 0), 100, 20, Menu::vertical, "Graph Type") , base_equation(Point(x_max() / 2, 0), 90, 20, "equation") , x_parameter(Point(100, 40), 20, 20, "t-paramter") , equation(Point(x_max() / 2, 40), 90, 20, "equation") , x_axis(Axis::x, Point(orig.x - 200, orig.y), 400, 20, "1 == 20") , y_axis(Axis::y, Point(orig.x, orig.y + 200), 400, 20, "1 == 20") , funct(mysin, r_min, r_max, orig, n_points, x_scale, y_scale) { attach(quit_button); attach(graph_button); attach(graph_type); attach(base_equation); attach(x_parameter); attach(equation); graph_type_menu.attach(new Button(Point(0, 0), 0, 0, "sin", cb_sin_graph)); graph_type_menu.attach(new Button(Point(0, 0), 0, 0, "cos", cb_cos_graph)); attach(graph_type_menu); x_axis.set_color(Color::black); y_axis.set_color(Color::black); attach(x_axis); attach(y_axis); funct.set_color(FL_BLACK); attach(funct); funct.set_color(Color::invisible); graph_type_menu.hide(); } void application_window::sin_graph() { graph_type_menu.hide(); graph_type.show(); base_equation.put("y = sin(x) * t"); g_type = sin_g; } void application_window::cos_graph() { graph_type_menu.hide(); graph_type.show(); base_equation.put("y = cos(x) * t"); g_type = cos_g; } void application_window::draw_graph() { // GRAPHS if(g_type == sin_g) { equation.put("y = sin(x) * " + x_parameter.get_string()); // most painful lambda to function pointer work-around ever. // saved the day: // https://deviorel.wordpress.com/2015/01/27/obtaining-function-pointers-from-lambdas-in-c/ int t = x_parameter.get_int(); auto la = [=](double x) { return sin(x) * t; }; static function< double(double) > static_variable; static_variable = la; double(*ptr)(double) = [](double x) { return static_variable(x); }; funct.reset( [](double x) { return static_variable(x); } , r_min , r_max , orig , n_points , x_scale , y_scale ); } if(g_type == cos_g) { equation.put("y = cos(x) * " + x_parameter.get_string()); int t = x_parameter.get_int(); auto la = [=](double x) { return cos(x) * t; }; static function< double(double) > static_variable; static_variable = la; double(*ptr)(double) = [](double x) { return static_variable(x); }; funct.reset( [](double x) { return static_variable(x); } , r_min , r_max , orig , n_points , x_scale , y_scale ); } funct.set_color(Color::visible); redraw(); } // ------------------------------ INTERFACE END------------------------- int main() try { application_window win(Point(100, 100), xmax, ymax + 20, "currency converter"); return gui_main(); } catch (exception& e) { cerr << "exception: " << e.what() << endl; char c; while (cin >> c&& c != ';'); return 1; } catch (...) { cerr << "exception\n"; char c; while (cin >> c && c != ';'); return 2; }