Moved to new folders

This commit is contained in:
2020-02-12 15:04:09 +01:00
parent 6645dca35f
commit 1a68ecad3d
162 changed files with 2 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
#include "GUI.h"
#include "std_lib_facilities.h"
#include <sstream>
using namespace Graph_lib;
void Button::attach(Graph_lib::Window& win)
{
pw = new Fl_Button(loc.x, loc.y, width, height, label.c_str());
pw->callback(reinterpret_cast<Fl_Callback*>(do_it), &win); // pass the window
own = &win;
}
int In_box::get_int()
{
Fl_Input& pi = reference_to<Fl_Input>(pw);
const char* p = pi.value();
if (!isdigit(p[0]))
return -999999;
return atoi(p);
}
string In_box::get_string()
{
Fl_Input& pi = reference_to<Fl_Input>(pw);
return string(pi.value());
}
void In_box::attach(Graph_lib::Window& win)
{
pw = new Fl_Input(loc.x, loc.y, width, height, label.c_str());
own = &win;
}
void Out_box::put(int i)
{
Fl_Output& po = reference_to<Fl_Output>(pw);
std::stringstream ss;
ss << i;
po.value(ss.str().c_str());
}
void Out_box::put(const string& s)
{
reference_to<Fl_Output>(pw).value(s.c_str());
}
void Out_box::attach(Graph_lib::Window& win)
{
pw = new Fl_Output(loc.x, loc.y, width, height, label.c_str());
own = &win;
}
int Menu::attach(Button& b)
{
b.width = width;
b.height = height;
switch (k) {
case horizontal:
b.loc = Point{loc.x + offset, loc.y};
offset += b.width;
break;
case vertical:
b.loc = Point{loc.x, loc.y + offset};
offset += b.height;
break;
}
selection.push_back(&b);
return int(selection.size() - 1);
}
int Menu::attach(Button* p)
{
return attach(*p);
}

View File

@@ -0,0 +1,167 @@
//
// 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)
{}
void redraw()
{
pw->redraw(); // Schedules redrawing of widget, as per FLTK docs
}
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;
virtual void clear_value()
{}
virtual void set_label(string l)
{
label = l;
pw->label(label.c_str());
}
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, nullptr)
{}
int get_int();
string get_string();
void clear_value() override
{
static_cast<Fl_Input*>(pw)->value("");
}
void attach(Window& win) override;
};
//------------------------------------------------------------------------------
struct Out_box : Widget
{
Out_box(Point xy, int w, int h, const string& s) : Widget(xy, w, h, s, nullptr)
{}
void put(int);
void put(const string&);
void attach(Graph_lib::Window& win) override;
};
//------------------------------------------------------------------------------
struct Menu : Widget
{
enum Kind { horizontal, vertical };
Menu(Point xy, int w, int h, Kind kk, const string& label)
: Widget(xy, w, h, label, nullptr), 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 (int i = 0; i < selection.size(); ++i)
selection[i].show();
}
void hide() // hide all buttons
{
for (int i = 0; i < selection.size(); ++i)
selection[i].hide();
}
void move(int dx, int dy) // move all buttons
{
for (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;
}
};
//------------------------------------------------------------------------------
} // namespace Graph_lib
#endif // GUI_GUARD

View File

@@ -0,0 +1,358 @@
#include "Graph.h"
#include <map>
namespace Graph_lib {
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());
fl_line_style(ls.style(), ls.width());
draw_lines();
fl_color(oldc); // reset color (to pevious) and style (to default)
fl_line_style(0);
}
// 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();
if (color().visibility()) // draw closing line:
fl_line(point(number_of_points() - 1).x, point(number_of_points() - 1).y, point(0).x,
point(0).y);
}
void Shape::move(int dx, int dy)
{
for (unsigned int i = 0; i < points.size(); ++i) {
points[i].x += dx;
points[i].y += dy;
}
}
void Lines::draw_lines() const
{
// if (number_of_points()%2==1) error("odd number of points in set of lines");
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);
}
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);
}
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;
}
}
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);
fl_color(color().as_int()); // reset color
}
if (color().visibility()) { // edge on top of fill
fl_color(color().as_int());
fl_rect(point(0).x, point(0).y, w, h);
}
}
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}); // axis line
if (1 < n) {
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) {
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(); // the line
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);
}
void Circle::draw_lines() const
{
if (fill_color().visibility()) { // fill
fl_color(fill_color().as_int());
fl_pie(point(0).x, point(0).y, r + r - 1, r + r - 1, 0, 360);
fl_color(color().as_int()); // reset color
}
if (color().visibility()) {
fl_color(color().as_int());
fl_arc(point(0).x, point(0).y, r + r, r + r, 0, 360);
}
}
void Ellipse::draw_lines() const
{
if (fill_color().visibility()) { // fill
fl_color(fill_color().as_int());
fl_pie(point(0).x, point(0).y, w + w - 1, h + h - 1, 0, 360);
fl_color(color().as_int()); // reset color
}
if (color().visibility()) {
fl_color(color().as_int());
fl_arc(point(0).x, point(0).y, w + w, h + h, 0, 360);
}
}
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()]);
}
std::map<string, Suffix::Encoding> suffix_map;
int init_suffix_map()
{
suffix_map["jpg"] = Suffix::jpg;
suffix_map["JPG"] = Suffix::jpg;
suffix_map["jpeg"] = Suffix::jpg;
suffix_map["JPEG"] = Suffix::jpg;
suffix_map["gif"] = Suffix::gif;
suffix_map["GIF"] = Suffix::gif;
suffix_map["bmp"] = Suffix::bmp;
suffix_map["BMP"] = Suffix::bmp;
return 0;
}
Suffix::Encoding get_encoding(const string& s)
// try to deduce type from file name using a lookup table
{
static int x = init_suffix_map(); // oneshot map init
string::const_iterator p = find(s.begin(), s.end(), '.');
if (p == s.end())
return Suffix::none; // no suffix
string suf(p + 1, s.end());
return suffix_map[suf];
}
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 bool{ff};
}
// somewhat overelaborate 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)) {
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) {
case Suffix::jpg:
p = new Fl_JPEG_Image(s.c_str());
break;
case Suffix::gif:
p = new Fl_GIF_Image(s.c_str());
break;
// case Suffix::bmp:
// p = new Fl_BMP_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);
}
} // namespace Graph_lib

View File

@@ -0,0 +1,623 @@
#ifndef GRAPH_GUARD
#define GRAPH_GUARD 1
#include "Point.h"
#include <vector>
//#include<string>
//#include<cmath>
#include "fltk.h"
#include "std_lib_facilities.h"
namespace Graph_lib {
// defense against ill-behaved Linux macros:
#undef major
#undef minor
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,
gray = FL_GRAY,
mid_gray = 48,
dark_gray = 38,
light_gray = 50
};
enum Transparency { invisible = 0, visible = 255 };
Color(Color_type cc) : v(visible), c(Fl_Color(cc))
{}
Color(Color_type cc, Transparency vv) : v(vv), c(Fl_Color(cc))
{}
Color(int cc) : v(visible), c(Fl_Color(cc))
{}
Color(Transparency vv) : v(vv), c(Fl_Color())
{}
int as_int() const
{
return c;
}
char visibility() const
{
return v;
}
void set_visibility(Transparency vv)
{
v = vv;
}
private:
unsigned char v; // 0 or 1 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, 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 (typename vector<T*>::size_type 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();
}
T& back()
{
return *v[v.size() - 1];
}
const T& back() const
{
return *v[v.size() - 1];
}
using iterator = typename vector<T*>::iterator;
iterator begin()
{
return v.begin();
}
auto end()
{
return v.end();
}
auto begin() const
{
return v.begin();
}
auto end() const
{
return v.end();
}
};
typedef double Fct(double);
class Shape
{ // deals with color and style, and holds sequence of lines
protected:
Shape()
{}
// Not by the book:
// Shape(initializer_list<Point> lst); // add() the Points to this Shape
// Changed init_list constructor, i.e. implemented at all
Shape(initializer_list<Point> lst)
{
for (Point p : lst)
add(p);
} // add() the Points to this Shape
void add(Point p)
{
points.push_back(p);
}
void set_point(int i, Point p)
{
points[i] = p;
}
public:
void draw() const; // deal with color and draw_lines
protected:
virtual void draw_lines() const; // simply draw the appropriate lines
public:
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];
}
int number_of_points() const
{
return int(points.size());
}
virtual ~Shape()
{}
Shape(const Shape&) = delete;
Shape& operator=(const Shape&) = delete;
private:
vector<Point> points; // not used by all shapes
Color lcolor{static_cast<int>(fl_color())};
Line_style ls{0};
Color fcolor{Color::invisible};
};
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 Fill
{
Fill() : no_fill(true), fcolor(0)
{}
Fill(Color c) : no_fill(false), fcolor(c)
{}
void set_fill_color(Color col)
{
fcolor = col;
}
Color fill_color()
{
return fcolor;
}
protected:
bool no_fill;
Color fcolor;
};
struct Line : Shape
{
Line(Point p1, Point p2)
{
add(p1);
add(p2);
}
};
struct Rectangle : Shape
{
Rectangle(Point xy, int ww, int hh) : h{hh}, w{ww}
{
if (h <= 0 || w <= 0)
error("Bad rectangle: non-positive side");
add(xy);
}
Rectangle(Point x, Point y) : h{y.y - x.y}, w{y.x - x.x}
{
if (h <= 0 || w <= 0)
error("Bad rectangle: first point is not top left");
add(x);
}
void draw_lines() const;
int height() const
{
return h;
}
int width() const
{
return w;
}
private:
int h; // height
int w; // width
};
bool intersect(Point p1, Point p2, Point p3, Point p4);
struct Open_polyline : Shape
{ // open sequence of lines
using Shape::Shape;
void add(Point p)
{
Shape::add(p);
}
void draw_lines() const;
};
struct Closed_polyline : Open_polyline
{ // closed sequence of lines
using Open_polyline::Open_polyline;
void draw_lines() const;
// void add(Point p) { Shape::add(p); }
};
struct Polygon : Closed_polyline
{ // closed sequence of non-intersecting lines
using Closed_polyline::Closed_polyline;
void add(Point p);
void draw_lines() const;
};
struct Lines : Shape
{ // indepentdent lines
Lines()
{}
Lines(initializer_list<Point> lst) : Shape{lst}
// Not equal to book constructor.
{
if (lst.size() % 2)
error("odd number of points for Lines");
}
Lines(initializer_list<pair<Point, Point>> lst)
{
// This is the constructor from the book, p.450 1st print.
for (auto p : lst)
add(p.first, p.second);
}
void draw_lines() const;
void add(Point p1, Point p2)
{
Shape::add(p1);
Shape::add(p2);
}
};
struct Text : Shape
{
// the point is the bottom left of the first letter
Text(Point x, const string& s) : lab{s}
{
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{fl_font()};
int fnt_sz{(14 < fl_size()) ? fl_size() : 14}; // at least 14 point
};
struct Axis : Shape
{
// representation left public
enum Orientation { x, y, z };
Axis(Orientation d, Point xy, int length, int nummber_of_notches = 0, string label = "");
void draw_lines() const;
void move(int dx, int dy);
void set_color(Color c);
Text label;
Lines notches;
// Orientation orin;
// int notches;
};
struct Circle : Shape
{
Circle(Point p, int rr) // center and radius
: r{rr}
{
add(Point{p.x - r, p.y - r});
}
void draw_lines() const;
Point center() const
{
return {point(0).x + r, point(0).y + r};
}
void set_radius(int rr)
{
r = rr;
}
int radius() const
{
return r;
}
private:
int r;
};
struct Ellipse : Shape
{
Ellipse(Point p, int ww,
int hh) // center, min, and max distance from center
: w{ww}, h{hh}
{
add(Point{p.x - ww, p.y - hh});
}
void draw_lines() const;
Point center() const
{
return {point(0).x + w, point(0).y + h};
}
Point focus1() const
{
return {center().x + int(sqrt(double(w * w - h * h))), center().y};
}
Point focus2() const
{
return {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 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);
}
};
struct Suffix
{
enum Encoding { none, jpg, gif, bmp };
};
Suffix::Encoding get_encoding(const string& s);
struct Image : Shape
{
Image(Point xy, string s, 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;
}
void move(int dx, int dy)
{
Shape::move(dx, dy);
p->draw(point(0).x, point(0).y);
}
private:
int w, h, cx, cy; // define "masking box" within image relative to
// position (cx,cy)
Fl_Image* p;
Text fn;
};
} // namespace Graph_lib
#endif

View File

@@ -0,0 +1,27 @@
CXX = clang++
DEBUG = -g
RELEASE = -O2
CXXFLAGS = -std=c++14 -Wall -Wpedantic -I../include
LINK = $(CXX)
CXXFLAGS += $(shell fltk-config --use-gl --use-images --cxxflags)
LDFLAGS += $(shell fltk-config --use-gl --use-images --ldflags)
LDSTATIC = $(shell fltk-config --use-gl --use-images --ldstaticflags)
SOURCES = Graph.cpp GUI.cpp Window.cpp
OBJECTS := $(SOURCES:.cpp=.o)
STATIC_LIB = Graph_lib.a
.SUFFIXES: .o .cpp
%.o: %.cpp
$(CXX) $(CXXFLAGS) $(DEBUG) -c $<
$(STATIC_LIB): $(OBJECTS)
ar -rv $(STATIC_LIB) $(OBJECTS)
$(RM) $(OBJECTS)
.PHONY: clean
clean:
$(RM) $(STATIC_LIB)
$(RM) $(OBJECTS)

View File

@@ -0,0 +1,23 @@
#ifndef POINT_GUARD
#define POINT_GUARD
namespace Graph_lib {
struct Point
{
int x;
int y;
};
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);
}
} // namespace Graph_lib
#endif

View File

@@ -0,0 +1,48 @@
#pragma once
#include "GUI.h" // for Simple_window only (doesn't really belong in Window.h)
using namespace Graph_lib;
// Simple_window is basic scaffolding for ultra-simple interaction with graphics
// it provides one window with one "next" button for ultra-simple animation
struct Simple_window : Graph_lib::Window
{
Simple_window(Point xy, int w, int h, const string& title)
: Window(xy, w, h, title),
next_button(Point{x_max() - 70, 0}, 70, 20, "Next", cb_next),
button_pushed(false)
{
attach(next_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 (!button_pushed)
Fl::wait();
button_pushed = false;
Fl::redraw();
}
Button next_button;
private:
bool button_pushed;
static void cb_next(Address,
Address addr) // callback for next_button
// {
// reference_to<Simple_window>(addr).next();
// }
{
static_cast<Simple_window*>(addr)->next();
}
void next()
{
button_pushed = true;
}
};

View File

@@ -0,0 +1,76 @@
#include "Window.h"
#include "Graph.h"
#include "GUI.h"
namespace Graph_lib {
Window::Window(int ww, int hh, const string& title) : Fl_Window(ww, hh, title.c_str()), w(ww), h(hh)
{
init();
}
Window::Window(Point xy, int ww, int hh, const string& title)
: Fl_Window(xy.x, xy.y, ww, hh, title.c_str()), w(ww), h(hh)
{
init();
}
void Window::init()
{
resizable(this);
show();
}
//----------------------------------------------------
void Window::draw()
{
Fl_Window::draw();
for (vector<Shape*>::size_type i = 0; i < shapes.size(); ++i)
shapes[i]->draw();
}
void Window::attach(Widget& widget)
{
begin(); // FLTK: begin attaching new Fl_Wigets to this window
widget.attach(*this); // let the Widget create its Fl_Wigits
end(); // FLTK: stop attaching new Fl_Wigets to this window
}
void Window::detach(Widget& b)
{
b.hide();
}
void Window::attach(Shape& s)
{
shapes.push_back(&s);
// s.attached = this;
}
void Window::detach(Shape& s)
{
for (vector<Shape*>::size_type i = shapes.size(); 0 < i;
--i) // guess last attached will be first released
if (shapes[i - 1] == &s)
shapes.erase(shapes.begin() + (i - 1)); //&shapes[i-1]);
}
void Window::put_on_top(Shape& p)
{
for (vector<Shape*>::size_type i = 0; i < shapes.size(); ++i) {
if (&p == shapes[i]) {
for (++i; i < shapes.size(); ++i)
shapes[i - 1] = shapes[i];
shapes[shapes.size() - 1] = &p;
return;
}
}
}
int gui_main()
{
return Fl::run();
}
} // namespace Graph_lib

View File

@@ -0,0 +1,56 @@
#ifndef WINDOW_GUARD
#define WINDOW_GUARD 1
#include "fltk.h"
#include "std_lib_facilities.h"
#include "Point.h"
namespace Graph_lib {
class Shape; // "forward declare" Shape
class Widget;
class Window : public Fl_Window {
public:
Window(int w, int h, const string& title ); // let the system pick the location
Window(Point xy, int w, int h, const string& title ); // top left corner in xy
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); }
using Fl_Window::resize;
void set_label(const string& s) { label(s.c_str()); }
void attach(Shape& s);
void attach(Widget& w);
void detach(Shape& s); // remove s from shapes
void detach(Widget& w); // remove w from window (deactivate callbacks)
void put_on_top(Shape& p); // put p on top of other shapes
void redraw() { Fl_Window::redraw(); }
// Schedules redrawing of widget, as per FLTK docs
protected:
void draw();
private:
int w,h; // window size
vector<Shape*> shapes; // shapes attached to window
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
}
#endif

View File

@@ -0,0 +1,20 @@
#ifndef FLTK_GUARD
#define FLTK_GUARD 1
#include "FL/Fl.H"
#include "FL/Fl_Window.H"
#include "FL/Fl_Button.H"
#include "FL/Fl_Input.H"
#include "FL/Fl_Output.H"
#include "FL/Fl_Multiline_Output.H"
#include <cstdlib> // for exit(0)
#include "FL/fl_draw.H"
#include "FL/Enumerations.H"
#include "FL/Fl_JPEG_Image.H"
#include "FL/Fl_GIF_Image.H"
#endif