Skip to content

Instantly share code, notes, and snippets.

@tschoonj
Last active August 29, 2015 14:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tschoonj/c40bb9cca6719478f000 to your computer and use it in GitHub Desktop.
Save tschoonj/c40bb9cca6719478f000 to your computer and use it in GitHub Desktop.
plplot extcairo gtkmm drawingarea
# ============================================================================
# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html
# ============================================================================
#
# SYNOPSIS
#
# AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional])
#
# DESCRIPTION
#
# Check for baseline language coverage in the compiler for the C++11
# standard; if necessary, add switches to CXXFLAGS to enable support.
#
# The first argument, if specified, indicates whether you insist on an
# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
# -std=c++11). If neither is specified, you get whatever works, with
# preference for an extended mode.
#
# The second argument, if specified 'mandatory' or if left unspecified,
# indicates that baseline C++11 support is required and that the macro
# should error out if no mode with that support is found. If specified
# 'optional', then configuration proceeds regardless, after defining
# HAVE_CXX11 if and only if a supporting mode is found.
#
# LICENSE
#
# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 11
m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[
template <typename T>
struct check
{
static_assert(sizeof(int) <= sizeof(T), "not big enough");
};
struct Base {
virtual void f() {}
};
struct Child : public Base {
virtual void f() override {}
};
typedef check<check<bool>> right_angle_brackets;
int a;
decltype(a) b;
typedef check<int> check_type;
check_type c;
check_type&& cr = static_cast<check_type&&>(c);
auto d = a;
auto l = [](){};
// Prevent Clang error: unused variable 'l' [-Werror,-Wunused-variable]
struct use_l { use_l() { l(); } };
// http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
// Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this
namespace test_template_alias_sfinae {
struct foo {};
template<typename T>
using member = typename T::member_type;
template<typename T>
void func(...) {}
template<typename T>
void func(member<T>*) {}
void test();
void test() {
func<foo>(0);
}
}
]])
AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl
m4_if([$1], [], [],
[$1], [ext], [],
[$1], [noext], [],
[m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl
m4_if([$2], [], [ax_cxx_compile_cxx11_required=true],
[$2], [mandatory], [ax_cxx_compile_cxx11_required=true],
[$2], [optional], [ax_cxx_compile_cxx11_required=false],
[m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])])
AC_LANG_PUSH([C++])dnl
ac_success=no
AC_CACHE_CHECK(whether $CXX supports C++11 features by default,
ax_cv_cxx_compile_cxx11,
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
[ax_cv_cxx_compile_cxx11=yes],
[ax_cv_cxx_compile_cxx11=no])])
if test x$ax_cv_cxx_compile_cxx11 = xyes; then
ac_success=yes
fi
m4_if([$1], [noext], [], [dnl
if test x$ac_success = xno; then
for switch in -std=gnu++11 -std=gnu++0x; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
$cachevar,
[ac_save_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXXFLAGS="$ac_save_CXXFLAGS"])
if eval test x\$$cachevar = xyes; then
CXXFLAGS="$CXXFLAGS $switch"
ac_success=yes
break
fi
done
fi])
m4_if([$1], [ext], [], [dnl
if test x$ac_success = xno; then
dnl HP's aCC needs +std=c++11 according to:
dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
for switch in -std=c++11 -std=c++0x +std=c++11; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
$cachevar,
[ac_save_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXXFLAGS="$ac_save_CXXFLAGS"])
if eval test x\$$cachevar = xyes; then
CXXFLAGS="$CXXFLAGS $switch"
ac_success=yes
break
fi
done
fi])
AC_LANG_POP([C++])
if test x$ax_cxx_compile_cxx11_required = xtrue; then
if test x$ac_success = xno; then
AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.])
fi
else
if test x$ac_success = xno; then
HAVE_CXX11=0
AC_MSG_NOTICE([No compiler with C++11 support was found])
else
HAVE_CXX11=1
AC_DEFINE(HAVE_CXX11,1,
[define if the compiler supports basic C++11 syntax])
fi
AC_SUBST(HAVE_CXX11)
fi
])
AC_INIT([plplot-blog],[0.1],[tom.schoonjans@me.com],,[https://tschoonj.github.io])
AC_PREREQ([2.60])
AC_CONFIG_SRCDIR([main.cpp])
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AC_CANONICAL_HOST
#m4_pattern_allow([AS_TR_SH])
AC_CONFIG_MACRO_DIR([.])
AC_USE_SYSTEM_EXTENSIONS
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
AC_PROG_CC
if test `AS_BASENAME([$CC])` = $CC ; then
AC_CHECK_PROG(CC_FULL, [$CC], $CC, [none])
#this next line may never be reached...
if test x$CC_FULL = "xnone" ; then
AC_MSG_ERROR([no C compiler was found on the system.])
fi
fi
AM_PROG_CC_C_O
AC_PROG_CXX
if test `AS_BASENAME([$CXX])` = $CXX ; then
AC_CHECK_PROG(CXX_FULL, [$CXX], $CXX, [none])
#this next line may never be reached...
if test x$CXX_FULL = "xnone" ; then
AC_MSG_ERROR([no C++ compiler was found on the system.])
fi
fi
AX_CXX_COMPILE_STDCXX_11(ext, mandatory)
LDFLAGS_EXTRA=""
OS_WINDOWS=0
OS_WINDOWS_32=0
OS_WINDOWS_64=0
case "$host" in
i686-*mingw*)
OS_WINDOWS_32=1
OS_WINDOWS=1
;;
x86_64-*mingw*)
OS_WINDOWS_64=1
OS_WINDOWS=1
;;
esac
AC_SUBST(WINDRES_ARCH)
AC_SUBST(OS_WINDOWS)
AM_CONDITIONAL([OS_WINDOWS],[test x$OS_WINDOWS = x1])
AC_SUBST(OS_WINDOWS_32)
AM_CONDITIONAL([OS_WINDOWS_32],[test x$OS_WINDOWS_32 = x1])
AC_SUBST(OS_WINDOWS_64)
AM_CONDITIONAL([OS_WINDOWS_64],[test x$OS_WINDOWS_64 = x1])
#look for xraylib
#initialize pkg-config
PKG_PROG_PKG_CONFIG
#search for xraylib and other modules
PKG_CHECK_MODULES([gtkmm],gtkmm-3.0 >= 3.12.0)
PKG_CHECK_MODULES([plplotcxx], [plplot-c++], ,
[PKG_CHECK_MODULES([plplotcxx], [plplotd-c++])])
#check for the extcairo device
result=
AC_MSG_CHECKING([for plplot extcairo device])
ac_save_CFLAGS="$CFLAGS"
CFLAGS=$plplotcxx_CFLAGS
AC_LANG_PUSH([C])
AC_TRY_COMPILE([
#include <plDevs.h>
],[
#ifndef PLD_extcairo
#error
#endif
],[
result=yes
AC_DEFINE([HAVE_EXTCAIRO], [], [extcairo found])
],[result=no])
AC_MSG_RESULT([$result])
if test x$result = xno ; then
AC_MSG_ERROR([plplot must be built with the extcairo device!])
fi
AC_LANG_POP
CFLAGS="$ac_save_CFLAGS"
AC_CONFIG_FILES([Makefile])
AC_CONFIG_HEADERS([config.h])
AC_OUTPUT
#include <gtkmm/application.h>
#include <glibmm/miscutils.h>
#include <glib.h>
#include "PLplotWindow.h"
#include <valarray>
int main(int argc, char **argv) {
Glib::set_application_name("plplot-test");
#if defined(G_OS_WIN32)
//windows requires a bit more work. This example sets the PLPLOT_LIB environment variable
//to ensure the PLplot data files are found at runtime
gchar *installation_dir = g_win32_get_package_installation_directory_of_module(NULL);
std::string path_to_plplot(Glib::build_filename(installation_dir, "Share", "plplot"));
std::cout << "path to plplot: " << path_to_plplot << std::endl;
Glib::setenv("PLPLOT_LIB", path_to_plplot, true);
g_free(installation_dir);
#endif
Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "eu.tomschoonjans.plplot");
//valarrays are underestimated IMHO
std::valarray<PLFLT> x_va(1000), y_va(1000);
for (unsigned int i = 0 ; i < 1000 ; i++) {
x_va[i] = 4*M_PI*i/999;
}
y_va = sin(x_va);
std::vector<PLFLT> x(std::begin(x_va), std::end(x_va)),
y(std::begin(y_va), std::end(y_va));
std::string x_title("x"), y_title("y = sinx(x)");
PLplotWindow window(x, y, x_title, y_title, "PLplotDrawingArea demonstration");
return app->run(window);
}
bin_PROGRAMS = plplot-test
plplot_test_SOURCES = main.cpp \
PLplotWindow.h \
PLplotWindow.cpp \
PLplotDrawingArea.h \
PLplotDrawingArea.cpp
plplot_test_CPPFLAGS= $(plplotcxx_CFLAGS) $(gtkmm_CFLAGS)
plplot_test_LDADD = $(plplotcxx_LIBS) $(gtkmm_LIBS)
#include "PLplotDrawingArea.h"
#include <iostream>
#include <algorithm>
#include <gdkmm/general.h>
#include <cmath>
PLplotDrawingArea::PLplotDrawingArea(
const std::vector<PLFLT> &_x,
const std::vector<PLFLT> &_y,
const std::string &_x_title,
const std::string &_y_title,
const std::string &_plot_title
) : x(_x),
y(_y),
x_title(_x_title),
y_title(_y_title),
plot_title(_plot_title),
start_event{-1.0, -1.0},
start_cairo{-1.0, -1.0},
end_event{-1.0, -1.0},
end_cairo{-1.0, -1.0},
selecting(false),
pls(0),
x_pl_range{*(x.begin()), *(x.end()-1)},
y_pl_range{*std::min_element(y.begin(), y.end()),
*std::max_element(y.begin(), y.end())}
{
add_events(Gdk::POINTER_MOTION_MASK |
Gdk::BUTTON_PRESS_MASK |
Gdk::BUTTON_RELEASE_MASK);
//connect our default signal handler
this->signal_select_region().connect(sigc::mem_fun(*this,
&PLplotDrawingArea::on_select_region));
}
void PLplotDrawingArea::on_select_region(double xmin, double xmax, double ymin, double ymax) {
//this function does nothing
//it is designed to be overridden by a derived class
}
void PLplotDrawingArea::set_region(double xmin, double xmax, double ymin, double ymax) {
if (xmin == xmax && ymin == ymax) {
//due to signal propagation, this function will actually be called twice on a double-click event,
//the second time after the plot has already been resized to its normal geometry
//this condition avoids the warning message...
return;
}
if (xmin >= xmax || ymin >= ymax ||
xmin < *(x.begin()) || xmax > *(x.end()-1) ||
ymin < *std::min_element(y.begin(), y.end()) ||
ymax > *std::max_element(y.begin(), y.end())) {
g_warning("PLplotDrawingArea::set_region(): Invalid arguments");
return;
}
x_pl_range[0] = xmin;
x_pl_range[1] = xmax;
y_pl_range[0] = ymin;
y_pl_range[1] = ymax;
this->get_window()->invalidate(true);
}
bool PLplotDrawingArea::on_button_press_event(GdkEventButton *event) {
Gtk::Allocation allocation = get_allocation();
const int width = allocation.get_width();
const int height = allocation.get_height();
start_event[0] = event->x;
start_event[1] = event->y;
start_cairo[0] = event->x;
start_cairo[1] = height - 1.0 * event->y;
end_event[0] = -1.0;
end_event[1] = -1.0;
end_cairo[0] = -1.0;
end_cairo[1] = -1.0;
//check if the starting coordinates are valid
if (start_cairo[0] < x_cr_range[0] ||
start_cairo[0] > x_cr_range[1] ||
start_cairo[1] < y_cr_range[0] ||
start_cairo[1] > y_cr_range[1]) {
g_warning("PLplotDrawingArea::on_button_press_event(): Invalid starting position in on_button_press_event");
selecting = false;
return true;
}
this->get_window()->invalidate(true);
selecting = true;
return false;
}
bool PLplotDrawingArea::on_button_release_event(GdkEventButton *event) {
if (!selecting)
return true;
Gtk::Allocation allocation = get_allocation();
const int width = allocation.get_width();
const int height = allocation.get_height();
end_event[0] = event->x;
end_event[1] = event->y;
end_cairo[0] = event->x;
end_cairo[1] = height - 1.0 * event->y;
//make sure we stay within the plot while selecting
if (end_cairo[0] > start_cairo[0]) {
//this 1E-10 subtraction is necessary to ensure calc_world works properly
//when dragging a box that touches the right axis.
end_cairo[0] = MIN(end_cairo[0], x_cr_range[1] - 1E-10);
}
else if (end_cairo[0] < start_cairo[0]) {
end_cairo[0] = MAX(end_cairo[0], x_cr_range[0]);
}
if (end_cairo[1] > start_cairo[1]) {
end_cairo[1] = MIN(end_cairo[1], y_cr_range[1]);
}
else if (end_cairo[1] < start_cairo[1]) {
end_cairo[1] = MAX(end_cairo[1], y_cr_range[0]);
}
selecting = false;
//emit signal!
//prepare plplot coordinates
//inspired by https://www.mail-archive.com/plplot-devel@lists.sourceforge.net/msg03079.html
double start_cairo_norm[2] = {start_cairo[0]/width, start_cairo[1]/height};
double end_cairo_norm[2] = {end_cairo[0]/width, end_cairo[1]/height};
double start_plplot[2];
double end_plplot[2];
int index;
//get the plot coordinates corresponding to the cairo coordinates
pls->calc_world(start_cairo_norm[0], start_cairo_norm[1],
start_plplot[0], start_plplot[1], index);
pls->calc_world(end_cairo_norm[0], end_cairo_norm[1],
end_plplot[0], end_plplot[1], index);
double start_plplot_def[2];
double end_plplot_def[2];
//ensure that the coordinates are within the extremes based on the x and y vectors
//in case of the full view, due to precision errors, the extremes calculated based on calc_world
//are actually slightly outside of these data extremes, meaning that it's not possible to drag the selection
//along the plot grid
start_plplot_def[0] = MAX(MIN(start_plplot[0], end_plplot[0]), *(x.begin()));
start_plplot_def[1] = MAX(MIN(start_plplot[1], end_plplot[1]), *std::min_element(y.begin(), y.end()));
end_plplot_def[0] = MIN(MAX(start_plplot[0], end_plplot[0]), *(x.end()-1));
end_plplot_def[1] = MIN(MAX(start_plplot[1], end_plplot[1]), *std::max_element(y.begin(), y.end()));
this->get_window()->invalidate(true);
_signal_select_region.emit(start_plplot_def[0], end_plplot_def[0], start_plplot_def[1], end_plplot_def[1]);
return true;
}
bool PLplotDrawingArea::on_motion_notify_event (GdkEventMotion *event) {
if (!selecting)
return true;
Gtk::Allocation allocation = get_allocation();
const int width = allocation.get_width();
const int height = allocation.get_height();
end_event[0] = event->x;
end_event[1] = event->y;
end_cairo[0] = event->x;
end_cairo[1] = height - 1.0 * event->y;
//make sure we stay within the plot while selecting
if (end_cairo[0] > start_cairo[0]) {
end_cairo[0] = MIN(end_cairo[0], x_cr_range[1]);
}
else if (end_cairo[0] < start_cairo[0]) {
end_cairo[0] = MAX(end_cairo[0], x_cr_range[0]);
}
if (end_cairo[1] > start_cairo[1]) {
end_cairo[1] = MIN(end_cairo[1], y_cr_range[1]);
}
else if (end_cairo[1] < start_cairo[1]) {
end_cairo[1] = MAX(end_cairo[1], y_cr_range[0]);
}
this->get_window()->invalidate(true);
return true;
}
void PLplotDrawingArea::draw_plot(const Cairo::RefPtr<Cairo::Context> &cr, plstream *_pls, int width, int height) {
_pls->sdev("extcairo");
_pls->spage(0.0, 0.0, width, height, 0, 0);
_pls->init();
Gdk::RGBA color = get_style_context()->get_color();
Gdk::Cairo::set_source_rgba(cr, color);
_pls->cmd(PLESC_DEVINIT, cr->cobj());
_pls->col0(0);
_pls->env(x_pl_range[0], x_pl_range[1],
y_pl_range[0], y_pl_range[1],
0, 0);
_pls->lab(x_title.c_str(), y_title.c_str(), plot_title.c_str());
_pls->col0(1);
_pls->line(x.size(), &x[0], &y[0]);
return;
}
bool PLplotDrawingArea::on_draw(const Cairo::RefPtr<Cairo::Context>& cr) {
Gtk::Allocation allocation = get_allocation();
const int width = allocation.get_width();
const int height = allocation.get_height();
if (pls)
delete pls;
pls = new plstream;
draw_plot(cr, pls, width, height);
if (selecting &&
start_cairo[0] >= 0.0 &&
start_cairo[1] >= 0.0 &&
end_cairo[0] >= 0.0 &&
end_cairo[1] >= 0.0) {
cr->set_line_width(2);
cr->set_source_rgb(0, 0, 0);
cr->rectangle(MIN(start_cairo[0], end_cairo[0]),
MIN(start_cairo[1], end_cairo[1]),
fabs(end_cairo[0] - start_cairo[0]),
fabs(end_cairo[1] - start_cairo[1]));
cr->stroke();
}
convert_plplot_to_cairo_coordinates(x_pl_range[0], y_pl_range[0],
x_cr_range[0], y_cr_range[0]);
convert_plplot_to_cairo_coordinates(x_pl_range[1], y_pl_range[1],
x_cr_range[1], y_cr_range[1]);
return true;
}
void PLplotDrawingArea::convert_plplot_to_cairo_coordinates(
double x_pl, double y_pl,
double &x_cr, double &y_cr) {
//inspired by http://www.mail-archive.com/plplot-devel@lists.sourceforge.net/msg02383.html
//but the last equation was incorrect and is fixed here
Gtk::Allocation allocation = get_allocation();
const int width = allocation.get_width();
const int height = allocation.get_height();
double nxmin, nxmax, nymin, nymax;
double wxmin, wxmax, wymin, wymax;
pls->gvpd(nxmin, nxmax, nymin, nymax);
pls->gvpw(wxmin, wxmax, wymin, wymax);
double xmin = width * nxmin;
double xmax = width * nxmax;
double ymin = height * nymin;
double ymax = height * nymax;
x_cr = xmin + ((xmax - xmin) * ((x_pl - wxmin) / (wxmax - wxmin)));
y_cr = ymin + ((ymax - ymin) * ((y_pl - wymin) / (wymax - wymin)));
}
#ifndef PLPLOTDRAWINGAREA_H
#define PLPLOTDRAWINGAREA_H
#include <gtkmm/drawingarea.h>
#include <plstream.h>
#include <string>
#include <vector>
typedef sigc::signal<void, double, double, double, double > type_signal_select_region;
class PLplotDrawingArea : public Gtk::DrawingArea {
private:
std::vector<PLFLT> x;
std::vector<PLFLT> y;
std::string x_title;
std::string y_title;
std::string plot_title;
double start_event[2];
double start_cairo[2];
double end_event[2];
double end_cairo[2];
bool selecting;
plstream *pls;
double x_pl_range[2];
double y_pl_range[2];
double x_cr_range[2];
double y_cr_range[2];
protected:
//our handler for the on_draw signal
virtual bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr);
// This is the default handler for the signal signal_select_region().
virtual void on_select_region(double xmin, double xmax, double ymin, double ymax);
bool on_button_press_event(GdkEventButton *event);
bool on_button_release_event(GdkEventButton *event);
bool on_motion_notify_event (GdkEventMotion *event);
type_signal_select_region _signal_select_region;
public:
PLplotDrawingArea(
const std::vector<PLFLT> &x,
const std::vector<PLFLT> &y,
const std::string &x_title,
const std::string &y_title,
const std::string &plot_title
);
void convert_plplot_to_cairo_coordinates(
double x_pl, double y_pl,
double &x_cr, double &y_cr);
virtual ~PLplotDrawingArea() {
if (pls)
delete pls;
}
type_signal_select_region signal_select_region() {
return _signal_select_region;
}
void set_region(double xmin, double xmax, double ymin, double ymax);
void draw_plot(const Cairo::RefPtr<Cairo::Context> &cr, plstream *_pls, int width, int height);
};
#endif
#include "PLplotWindow.h"
#include <gtkmm/printsettings.h>
#include <gtkmm/pagesetup.h>
#include <gtkmm/printoperation.h>
#include <gtkmm/filechooserdialog.h>
bool PLplotWindow::on_plplot_drawing_area_double_click(GdkEventButton *event,
double xmin, double xmax, double ymin, double ymax) {
if (event->type == GDK_2BUTTON_PRESS) {
plplot_drawing_area.set_region(xmin, xmax, ymin, ymax);
}
return false;
}
PLplotWindow::PLplotWindow(std::vector<PLFLT> &x, std::vector<PLFLT> &y,
std::string x_title, std::string y_title,
std::string plot_title) : plplot_drawing_area(x, y, x_title,
y_title, plot_title), print_button("Print"), saveas_button("Save as"),
quit_button("Quit"), buttons(Gtk::ORIENTATION_HORIZONTAL) {
set_default_size(720, 580);
//sadly the fixed aspect ratio does not work properly on OS X
//see https://bugzilla.gnome.org/show_bug.cgi?id=723859
//I submitted a patch for this...
Gdk::Geometry geometry;
geometry.min_aspect = geometry.max_aspect = double(720)/double(580);
set_geometry_hints(*this, geometry, Gdk::HINT_ASPECT);
set_title("PLplot Gtkmm DrawingArea example");
//resize on select
//signal_select_region's default handler doesnt do anything so
//in order for the selection box to do something at all, two options are available:
//1) derive PLplotDrawingArea and define your own on_select_region method
//2) if using an instance of PLplotDrawingArea, connect a signal to signal_select_region, this is done here
//both options are encouraged to use PLplotDrawingArea::set_region, possibly combined with further calls...
plplot_drawing_area.signal_select_region().connect(sigc::mem_fun(plplot_drawing_area, &PLplotDrawingArea::set_region));
//the double click event is not handled at all by PLplotDrawingArea (although I could...)
plplot_drawing_area.signal_button_press_event().connect(sigc::bind(sigc::mem_fun(*this, &PLplotWindow::on_plplot_drawing_area_double_click), *(x.begin()), *(x.end()-1), *std::min_element(y.begin(), y.end()), *std::max_element(y.begin(), y.end())));
quit_button.signal_clicked().connect(sigc::mem_fun(*this, &PLplotWindow::on_quit_button_clicked));
print_button.signal_clicked().connect(sigc::mem_fun(*this, &PLplotWindow::on_print_button_clicked));
saveas_button.signal_clicked().connect(sigc::mem_fun(*this, &PLplotWindow::on_saveas_button_clicked));
buttons.pack_start(print_button);
buttons.pack_start(saveas_button);
buttons.pack_start(quit_button);
buttons.set_layout(Gtk::BUTTONBOX_CENTER);
buttons.set_spacing(10);
buttons.set_vexpand(false);
buttons.set_hexpand(true);
plplot_drawing_area.set_hexpand(true);
plplot_drawing_area.set_vexpand(true);
grid.attach(buttons, 0, 0, 1, 1);
grid.attach(plplot_drawing_area, 0, 1, 1, 1);
grid.set_column_spacing(5);
grid.set_row_spacing(5);
grid.set_row_homogeneous(false);
grid.set_column_homogeneous(false);
add(grid);
set_border_width(10);
grid.show_all();
//plplot_drawing_area.show();
}
void PLplotWindow::on_draw_page(const Glib::RefPtr<Gtk::PrintContext>& context, int page_nr) {
::Cairo::RefPtr< ::Cairo::Context> cr = context->get_cairo_context();
plstream pls;
plplot_drawing_area.draw_plot(cr, &pls, 842, 595);
}
void PLplotWindow::on_print_button_clicked() {
//print settings
Glib::RefPtr<Gtk::PrintSettings> print_settings = Gtk::PrintSettings::create();
print_settings->set_orientation(Gtk::PAGE_ORIENTATION_LANDSCAPE);
print_settings->set_paper_size(Gtk::PaperSize(Gtk::PAPER_NAME_A4));
Glib::RefPtr<Gtk::PageSetup> page_setup = Gtk::PageSetup::create();
page_setup->set_orientation(Gtk::PAGE_ORIENTATION_LANDSCAPE);
page_setup->set_paper_size_and_default_margins(Gtk::PaperSize(Gtk::PAPER_NAME_A4));
Glib::RefPtr<Gtk::PrintOperation> operation = Gtk::PrintOperation::create();
operation->set_print_settings(print_settings);
operation->set_default_page_setup(page_setup);
operation->set_show_progress(true);
operation->set_track_print_status(true);
operation->set_use_full_page(true);
operation->signal_draw_page().connect(sigc::mem_fun(*this, &PLplotWindow::on_draw_page));
operation->set_n_pages(1);
if (Gtk::PRINT_OPERATION_RESULT_APPLY != operation->run(Gtk::PRINT_OPERATION_ACTION_PRINT_DIALOG, *this)) {
//error handling
}
return;
}
void PLplotWindow::on_saveas_button_clicked() {
Gtk::FileChooserDialog dialog(*this, "Save as", Gtk::FILE_CHOOSER_ACTION_SAVE);
dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL);
dialog.add_button("Select", Gtk::RESPONSE_OK);
dialog.set_do_overwrite_confirmation(true);
Glib::RefPtr<Gtk::FileFilter> filter_eps = Gtk::FileFilter::create();
filter_eps->add_pattern("*.eps");
filter_eps->set_name("EPS");
dialog.add_filter(filter_eps);
Glib::RefPtr<Gtk::FileFilter> filter_png = Gtk::FileFilter::create();
filter_png->add_pattern("*.png");
filter_png->set_name("PNG");
dialog.add_filter(filter_png);
Glib::RefPtr<Gtk::FileFilter> filter_pdf = Gtk::FileFilter::create();
filter_pdf->add_pattern("*.pdf");
filter_pdf->set_name("PDF");
dialog.add_filter(filter_pdf);
if (dialog.run() == Gtk::RESPONSE_OK) {
std::string filename = dialog.get_filename();
Glib::RefPtr<Gtk::FileFilter> filter_selected = dialog.get_filter();
if (filter_selected->get_name() == "EPS") {
if (filename.compare(filename.length()-4, std::string::npos, ".eps") != 0)
filename += ".eps";
Cairo::RefPtr<Cairo::PsSurface> surface = Cairo::PsSurface::create(filename, 842, 595);
surface->set_eps(true);
Cairo::RefPtr<Cairo::Context> cr = Cairo::Context::create(surface);
plstream pls;
plplot_drawing_area.draw_plot(cr, &pls, 842, 595);
cr->show_page();
}
else if (filter_selected->get_name() == "PNG") {
if (filename.compare(filename.length()-4, std::string::npos, ".png") != 0)
filename += ".png";
Cairo::RefPtr<Cairo::ImageSurface> surface = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, 842, 595);
Cairo::RefPtr<Cairo::Context> cr = Cairo::Context::create(surface);
plstream pls;
plplot_drawing_area.draw_plot(cr, &pls, 842, 595);
surface->write_to_png(filename);
}
else if (filter_selected->get_name() == "PDF") {
if (filename.compare(filename.length()-4, std::string::npos, ".pdf") != 0)
filename += ".pdf";
Cairo::RefPtr<Cairo::PdfSurface> surface = Cairo::PdfSurface::create(filename, 842, 595);
Cairo::RefPtr<Cairo::Context> cr = Cairo::Context::create(surface);
plstream pls;
plplot_drawing_area.draw_plot(cr, &pls, 842, 595);
cr->show_page();
}
}
return;
}
#ifndef PLPLOTWINDOW_H
#define PLPLOTWINDOW_H
#include <gtkmm/window.h>
#include <gtkmm/grid.h>
#include <gtkmm/buttonbox.h>
#include <gtkmm/button.h>
#include "PLplotDrawingArea.h"
#include <plstream.h>
#include <vector>
#include <string>
#include <cmath>
#include <iostream>
#include <gtkmm/printcontext.h>
class PLplotWindow : public Gtk::Window {
private:
PLplotDrawingArea plplot_drawing_area;
bool on_plplot_drawing_area_double_click(GdkEventButton *event,
double xmin, double xmax, double ymin, double ymax);
Gtk::Grid grid;
Gtk::Button print_button;
Gtk::Button saveas_button;
Gtk::Button quit_button;
Gtk::ButtonBox buttons;
void on_quit_button_clicked() {
get_application()->remove_window(*this);
return;
}
void on_saveas_button_clicked();
void on_print_button_clicked();
void on_draw_page(const Glib::RefPtr<Gtk::PrintContext>& context, int page_nr);
public:
PLplotWindow(std::vector<PLFLT> &x, std::vector<PLFLT> &y,
std::string x_title = "X-axis", std::string y_title = "Y-axis",
std::string plot_title = "");
virtual ~PLplotWindow() {}
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment