Last active
August 29, 2015 14:24
-
-
Save tschoonj/c40bb9cca6719478f000 to your computer and use it in GitHub Desktop.
plplot extcairo gtkmm drawingarea
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ============================================================================ | |
# 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 <[email protected]> | |
# Copyright (c) 2012 Zack Weinberg <[email protected]> | |
# Copyright (c) 2013 Roy Stogner <[email protected]> | |
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <[email protected]> | |
# | |
# 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 | |
]) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
AC_INIT([plplot-blog],[0.1],[[email protected]],,[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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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/[email protected]/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/[email protected]/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))); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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