diff --git a/frontend/Makefile b/frontend/Makefile new file mode 100755 index 0000000..20ba1d2 --- /dev/null +++ b/frontend/Makefile @@ -0,0 +1,24 @@ +# adding cairo.pc +export PKG_CONFIG_PATH:=/usr/lib/x86_64-linux-gnu/pkgconfig/ + +# programs +CC = gcc +PC=pkg-config +RM=rm + +TARGET=frontend +OBJS=Plot.o XWindow.o cairotest.o + +CFLAGS = -Wall `$(PC) --cflags cairomm-xlib-1.0` +LIBS = -lm `$(PC) --libs cairomm-xlib-1.0` +INC = -I/usr/include/cairomm-1.0/ + +all: $(OBJS) + $(CC) $(OBJS) $(LIBS) -o $(TARGET) + +%.o: %.cpp + $(CC) $(CFLAGS) $(INC) -c -o $@ $< + +clean: + $(RM) frontend + $(RM) $(OBJS) diff --git a/frontend/Plot.cpp b/frontend/Plot.cpp new file mode 100644 index 0000000..df81556 --- /dev/null +++ b/frontend/Plot.cpp @@ -0,0 +1,108 @@ +#include +#include + +#include + +#include "Plot.h" + +PlotSeries::PlotSeries(PlotSeries::Style style, Color color) + : color(color), style(style) +{ } + +void PlotSeries::draw(RefPtr ctx) { + ctx->set_source_rgb(color.red, color.green, color.blue); /* set series color */ + + /* determine maxima and minima for autoscale */ + double min = DBL_MAX, max = DBL_MIN; + for (std::list::iterator it = begin(); it != end(); it++) { + if (*it > max) max = *it; + if (*it < min) min = *it; + } + + /* stroke */ + + int width = 800;//dynamic_cast>(ctx->get_target())->get_width(); + int height = 400;//dynamic_cast>(ctx->get_target())->get_height(); + + ctx->move_to(Plot::PADDING, (height/2) + (height-2*Plot::PADDING) * (front()/max)); + + int i = 0; + for (std::list::iterator it = begin(); it != end(); it++) { + i++; + ctx->line_to(i * 2 + Plot::PADDING, (height/2) + (height-2*Plot::PADDING) * (*it/max*0.5)); + } + ctx->stroke(); +} + +Plot::Plot(int width, int height) + : width(width), height(height) +{ + window = XWindow::create("Frontend", 1, 1, width, height); + surface = XlibSurface::create(window->getDisplay(), window->getWindow(), window->getVisual(), width, height); +} + +void Plot::draw() { + RefPtr ctx = Context::create(surface); + ctx->set_antialias(ANTIALIAS_SUBPIXEL); + + /* background */ + ctx->set_source_rgb(0, 0, 0); /* black */ + ctx->paint(); + + ctx->set_source_rgb(0, 0.7, 0.1); /* axis & tick color */ + drawAxes(ctx); + drawTicks(ctx); + + for (std::list::iterator it = series.begin(); it != series.end(); it++) { + (*it)->draw(ctx); + } +} + +void Plot::drawAxes(RefPtr ctx) { + ctx->set_line_width(1.8); + + /* x-axis */ + ctx->move_to(PADDING, height-PADDING); + ctx->line_to(width-PADDING, height-PADDING); + ctx->stroke(); + + /* y-axis */ + ctx->move_to(PADDING, height-PADDING); + ctx->line_to(PADDING, PADDING); + ctx->stroke(); + + /* arrows (arcs) */ + ctx->move_to(width-PADDING-2, height-PADDING-4); + ctx->line_to(width-PADDING+5, height-PADDING); + ctx->line_to(width-PADDING-2, height-PADDING+4); + ctx->stroke(); + + ctx->move_to(PADDING-4, PADDING+2); + ctx->line_to(PADDING, PADDING-5); + ctx->line_to(PADDING+4, PADDING+2); + ctx->stroke(); +} + +void Plot::drawTicks(RefPtr ctx) { + int ticks = 20; + int intv_x = (width-2*PADDING)/ticks; + int intv_y = (height-2*PADDING)/ticks; + + ctx->set_line_width(1); + + for (int i = 0; i < ticks; i++) { + /* x-axis */ + ctx->move_to(PADDING + i*intv_x, height-PADDING-3); + ctx->line_to(PADDING + i*intv_x, height-PADDING+3); + ctx->stroke(); + + /* y-axis */ + ctx->move_to(PADDING-3, PADDING + (i+1)*intv_y); + ctx->line_to(PADDING+3, PADDING + (i+1)*intv_y); + ctx->stroke(); + } +} + +Plot::~Plot() { + +} diff --git a/frontend/Plot.h b/frontend/Plot.h new file mode 100644 index 0000000..e43f0c8 --- /dev/null +++ b/frontend/Plot.h @@ -0,0 +1,50 @@ +#ifndef _PLOT_H_ +#define _PLOT_H_ + +#include +#include +#include + +#include "XWindow.h" + +using namespace Cairo; + +struct Color { + double red, green, blue, alpha; +}; + +class PlotSeries : public std::list { + + public: + Color color; + enum Style { STYLE_LINE, STYLE_SPLINE, STYLE_SCATTER } style; + + PlotSeries(enum Style style, Color color); + void draw(RefPtr ctx); +}; + +class Plot { + + friend class PlotSeries; + + public: + Plot(int width = 400, int height = 300); + virtual ~Plot(); + + void draw(); + + std::list series; + + protected: + RefPtr window; + RefPtr surface; + + int width, height; + + void drawAxes(RefPtr ctx); + void drawTicks(RefPtr ctx); + + static const int PADDING = 20; +}; + +#endif /* _PLOT_H_ */ diff --git a/frontend/Plot.o b/frontend/Plot.o new file mode 100644 index 0000000..f15a33b Binary files /dev/null and b/frontend/Plot.o differ diff --git a/frontend/XWindow.cpp b/frontend/XWindow.cpp new file mode 100644 index 0000000..5ae2ab2 --- /dev/null +++ b/frontend/XWindow.cpp @@ -0,0 +1,60 @@ +#include +#include +#include + +#include "XWindow.h" + +Display * XWindow::display = NULL; +int XWindow::windows = 0; +int XWindow::screen = 0; + +XException::XException(const char *reason) { + fprintf(stderr, "%s\n", reason); + exit(EXIT_FAILURE); +} + +XWindow::XWindow(const char *title, int x, int y, int width, int height, unsigned long background) { + Window rootWindow; + + screen = XDefaultScreen(display); + rootWindow = XRootWindow(display, screen); + + window = XCreateSimpleWindow(display, rootWindow, x, y, width, height, 0, 0, background); + + XStoreName(display, window, title); + XSelectInput(display, window, ExposureMask | ButtonPressMask); + XMapWindow(display, window); +} + +XWindow::~XWindow() { + windows--; + + if (windows == 0) { + disconnect(); + } +} + +Display * XWindow::getDisplay() { + if (display == NULL) { + throw new XException("There exists no connection to an XServer!"); + } + + return display; +} + +void XWindow::connect(std::string display_name) { + display = XOpenDisplay(display_name.c_str()); + + if (display == NULL) { + throw XException("Cannot open display!"); + } +} + +void XWindow::disconnect() { + XCloseDisplay(display); +} + +Cairo::RefPtr XWindow::create(const char *title, int x, int y, int width, int height, unsigned long background) { + XWindow *win = new XWindow(title, x, y, width, height, background); + return Cairo::RefPtr(win); +} diff --git a/frontend/XWindow.h b/frontend/XWindow.h new file mode 100644 index 0000000..65ea58b --- /dev/null +++ b/frontend/XWindow.h @@ -0,0 +1,49 @@ +#ifndef _XWINDOW_H_ +#define _XWINDOW_H_ + +#include +#include + +#include + +class XException { + public: + XException(const char * reason); +}; + +class XWindow { + + public: + XWindow( + const char *title, + int x = 1, int y = 1, + int width = 800, int height = 600, + unsigned long background = 0 + ); + + virtual ~XWindow(); + + Window getWindow() { return window; }; + Visual * getVisual() { return XDefaultVisual(display, screen); }; + + static Display * getDisplay(); + + static void connect(std::string display); + static void disconnect(); + + static Cairo::RefPtr create( + const char *title, + int x = 1, int y = 1, + int width = 800, int height = 600, + unsigned long background = 0 + ); + +protected: + Window window; + + static Display *display; + static int screen; + static int windows; /* reference counter to open windows */ +}; + +#endif /* _XWINDOW_H_ */ diff --git a/frontend/XWindow.o b/frontend/XWindow.o new file mode 100644 index 0000000..53ef8be Binary files /dev/null and b/frontend/XWindow.o differ diff --git a/frontend/cairotest.cpp b/frontend/cairotest.cpp new file mode 100644 index 0000000..7542816 --- /dev/null +++ b/frontend/cairotest.cpp @@ -0,0 +1,46 @@ +#include "XWindow.h" +#include "Plot.h" + +#include + +#include +#include + +using namespace Cairo; + +int main(int argc, char *argv[]) { + XWindow::connect(":0"); // TODO parse from argv + + XEvent e; + Color blue = { 0, 0, 1 }; + Color red = { 1, 0, 0 }; + Plot testPlot(800, 400); + Plot testPlot2(800, 400); + + PlotSeries *demo1 = new PlotSeries(PlotSeries::STYLE_LINE, blue); + PlotSeries *demo2 = new PlotSeries(PlotSeries::STYLE_LINE, red); + testPlot.series.push_back(demo1); + testPlot2.series.push_back(demo2); + + double phi = 0; + double last = 0; + + while (1) { + phi += 1e-1; + + last += -10 + rand()%21; + + demo2->push_back(last); + + if (demo2->size() > 400) demo2->pop_front(); + + demo1->clear(); + for (int i = 0; i < 300; i++) { + demo1->push_back(0.7*sin(i*phi/1e3)*sin(i * (M_PI/30.0) + phi)); + } + + usleep(0.2*1e5); + testPlot.draw(); + testPlot2.draw(); + } +} diff --git a/frontend/cairotest.o b/frontend/cairotest.o new file mode 100644 index 0000000..088565d Binary files /dev/null and b/frontend/cairotest.o differ