diff options
Diffstat (limited to 'include/toys')
-rw-r--r-- | include/toys/lpe-framework.h | 77 | ||||
-rw-r--r-- | include/toys/path-cairo.h | 57 | ||||
-rw-r--r-- | include/toys/toy-framework-2.h | 451 |
3 files changed, 585 insertions, 0 deletions
diff --git a/include/toys/lpe-framework.h b/include/toys/lpe-framework.h new file mode 100644 index 0000000..9de5aa0 --- /dev/null +++ b/include/toys/lpe-framework.h @@ -0,0 +1,77 @@ +/** + * \file lpe-framework.h + * \brief A framework for writing an Inkscape Live Path Effect toy. + * + * Instead of using the standard toy framework, one can use this LPE + * framework when creating an LPE for Inkscape. When new 2geom functions + * are required for the LPE, adding this functionality directly in Inkscape + * greatly increases compile times. Using this framework, one only has to + * rebuild 2geom, which speeds up development considerably. (Think about + * how much of Inkscape will have to be rebuild if you change/add something + * in point.h ...) + * An example of how to use this framework is lpe.test.cpp. + *//* + * Copyright 2009 Johan Engelen <goejendaagh@zonnet.nl> + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + */ + +#ifndef _2GEOM_LPE_TOY_FRAMEWORK_H_ +#define _2GEOM_LPE_TOY_FRAMEWORK_H_ + +/** + * This should greatly simplify creating toy code for a Live Path Effect (LPE) for Inkscape + */ + + +#include <toys/toy-framework-2.h> +#include <2geom/pathvector.h> + +class LPEToy: public Toy { +public: + LPEToy(); + void draw(cairo_t *cr, std::ostringstream *notify, int width, int height, bool save, std::ostringstream *timer_stream) override; + virtual Geom::PathVector + doEffect_path (Geom::PathVector const & path_in); + virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > + doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in); + + /** this boolean defaults to false, it concatenates the input path to one pwd2, + * instead of normally 'splitting' the path into continuous pwd2 paths. */ + bool concatenate_before_pwd2; + PointSetHandle curve_handle; +}; + +#endif // _2GEOM_LPE_TOY_FRAMEWORK_H_ +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: + */ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/include/toys/path-cairo.h b/include/toys/path-cairo.h new file mode 100644 index 0000000..4c0403f --- /dev/null +++ b/include/toys/path-cairo.h @@ -0,0 +1,57 @@ +#ifndef PATH_CAIRO +#define PATH_CAIRO + + +#include <cairo.h> +#include <2geom/line.h> +#include <2geom/sbasis.h> +#include <2geom/sbasis-2d.h> +#include <2geom/d2.h> +#include <2geom/piecewise.h> +#include <2geom/path.h> +#include <2geom/convex-hull.h> +#include <vector> +#include <string> + +typedef struct _cairo cairo_t; + +void cairo_curve(cairo_t *cr, Geom::Curve const &c); +void cairo_rectangle(cairo_t *cr, Geom::Rect const &r); +void cairo_convex_hull(cairo_t *cr, Geom::ConvexHull const &r); +void cairo_path(cairo_t *cr, Geom::Path const &p); +void cairo_path(cairo_t *cr, Geom::PathVector const &p); +void cairo_path_stitches(cairo_t *cr, Geom::Path const &p); +void cairo_path_stitches(cairo_t *cr, Geom::PathVector const &p); + +void cairo_d2_sb(cairo_t *cr, Geom::D2<Geom::SBasis> const &p); +void cairo_d2_sb_handles(cairo_t *cr, Geom::D2<Geom::SBasis> const &p); +void cairo_d2_sb2d(cairo_t* cr, Geom::D2<Geom::SBasis2d> const &sb2, Geom::Point dir, double width); +void cairo_sb2d(cairo_t* cr, Geom::SBasis2d const &sb2, Geom::Point dir, double width); + +void cairo_d2_pw_sb(cairo_t *cr, Geom::D2<Geom::Piecewise<Geom::SBasis> > const &p); +void cairo_pw_d2_sb(cairo_t *cr, Geom::Piecewise<Geom::D2<Geom::SBasis> > const &p); + + +void draw_line(cairo_t *cr, const Geom::Line& l, const Geom::Rect& r); +void draw_line(cairo_t *cr, Geom::Point n, double d, Geom::Rect r); +void draw_line(cairo_t *cr, Geom::Point a, Geom::Point b, Geom::Rect r); + +void draw_line_seg(cairo_t *cr, Geom::Point a, Geom::Point b); +void draw_line_seg_with_arrow(cairo_t *cr, Geom::Point a, Geom::Point b, double dangle = 15*M_PI/180, double radius = 20); +void draw_spot(cairo_t *cr, Geom::Point h); +void draw_handle(cairo_t *cr, Geom::Point h); +void draw_cross(cairo_t *cr, Geom::Point h); +void draw_circ(cairo_t *cr, Geom::Point h); +void draw_ray(cairo_t *cr, Geom::Point h, Geom::Point dir); +void draw_ray(cairo_t *cr, const Geom::Ray& ray, const Geom::Rect& r); +void draw_line_segment(cairo_t *cr, const Geom::LineSegment& ls, const Geom::Rect& r); + +void cairo_move_to(cairo_t *cr, Geom::Point p1); +void cairo_line_to(cairo_t *cr, Geom::Point p1); +void cairo_curve_to(cairo_t *cr, Geom::Point p1, Geom::Point p2, Geom::Point p3); + +// H in [0,360) +// S, V, R, G, B in [0,1] +void convertHSVtoRGB(const double H, const double S, const double V, + double& R, double& G, double& B); +#endif diff --git a/include/toys/toy-framework-2.h b/include/toys/toy-framework-2.h new file mode 100644 index 0000000..5504dfd --- /dev/null +++ b/include/toys/toy-framework-2.h @@ -0,0 +1,451 @@ + +#ifndef _2GEOM_TOY_FRAMEWORK2_H_ +#define _2GEOM_TOY_FRAMEWORK2_H_ + + + +#include <cairo.h> +#include <gtk/gtk.h> +#include <iostream> +#include <sstream> +#include <string> +#include <utility> +#include <vector> + +#include <assert.h> +#include <2geom/exception.h> +#include <2geom/point.h> +#include <2geom/geom.h> +#include <2geom/sbasis.h> +#include <2geom/d2.h> +#include <sched.h> +#include <toys/path-cairo.h> + +using std::vector; + +//Utility functions +double uniform(); + +void draw_text(cairo_t *cr, Geom::Point pos, const char* txt, bool bottom = false, const char* fontdesc = "Sans"); +void draw_text(cairo_t *cr, Geom::Point pos, const std::string& txt, bool bottom = false, const std::string& fontdesc = "Sans"); +void draw_number(cairo_t *cr, Geom::Point pos, int num, std::string name=std::string(), bool bottom = true); +void draw_number(cairo_t *cr, Geom::Point pos, unsigned num, std::string name=std::string(), bool bottom = true); +void draw_number(cairo_t *cr, Geom::Point pos, double num, std::string name=std::string(), bool bottom = true); + +struct colour{ + double r,g,b,a; + colour(double r, double g, double b, double a) : r(r), g(g), b(b), a(a) {} + static colour from_hsv( float H, // hue shift (radians) + float S, // saturation shift (scalar) + float V, // value multiplier (scalar) + float A + ); + static colour from_hsl( float H, // hue shift (radians) + float S, // saturation shift (scalar) + float L, // value multiplier (scalar) + float A + ); +}; +void cairo_set_source_rgba(cairo_t* cr, colour c); + +class Handle{ +public: + std::string name; + float rgb[3]; + Handle() {rgb[0] = rgb[1] = rgb[2] = 0;} + virtual ~Handle() {} + virtual void draw(cairo_t *cr, bool annotes=false) = 0; + + virtual void* hit(Geom::Point pos) = 0; + virtual void move_to(void* hit, Geom::Point om, Geom::Point m) = 0; + virtual void load(FILE* f)=0; + virtual void save(FILE* f)=0; +}; + +class Toggle : public Handle{ +public: + Geom::Rect bounds; + const char* text; + bool on; + Toggle() : bounds(Geom::Point(0,0), Geom::Point(0,0)), text(""), on(false) {} + Toggle(const char* txt, bool v) : bounds(Geom::Point(0,0), Geom::Point(0,0)), text(txt), on(v) {} + Toggle(Geom::Rect bnds, const char* txt, bool v) : bounds(bnds), text(txt), on(v) {} + void draw(cairo_t *cr, bool annotes = false) override; + void toggle(); + void set(bool state); + void handle_click(GdkEventButton* e); + void* hit(Geom::Point pos) override; + void move_to(void* /*hit*/, Geom::Point /*om*/, Geom::Point /*m*/) override { /* not implemented */ } + void load(FILE* /*f*/) override { /* not implemented */ } + void save(FILE* /*f*/) override { /* not implemented */ } +}; + + +template< typename T> +class VectorHandle : public Handle +{ + public: + VectorHandle() + : m_handles() + { + } + void draw(cairo_t *cr, bool annotes=false) override + { + for (iterator it = m_handles.begin(); it != m_handles.end(); ++it) + it->draw(cr, annotes); + } + + void* hit(Geom::Point pos) override + { + void* result = NULL; + for (iterator it = m_handles.begin(); it != m_handles.end(); ++it) + { + result = it->hit(pos); + if (result != NULL) break; + } + return result; + } + + void move_to(void* hit, Geom::Point om, Geom::Point m) override + { + if (hit != NULL) + { + static_cast<T*>(hit)->move_to(hit, om, m); + } + } + + void load(FILE* f) override + { + for (iterator it = m_handles.begin(); it != m_handles.end(); ++it) + it->load(f); + } + + void save(FILE* f) override + { + for (iterator it = m_handles.begin(); it != m_handles.end(); ++it) + it->save(f); + } + + void clear() + { + m_handles.clear(); + } + + void reserve(size_t sz) + { + m_handles.reserve(sz); + } + + size_t size() const + { + return m_handles.size(); + } + + void push_back (const T& _handle) + { + m_handles.push_back(_handle); + } + + const T& operator[] (size_t i) const + { + return m_handles.at(i); + } + + T& operator[] (size_t i) + { + return m_handles.at(i); + } + + private: + typedef typename std::vector<T>::iterator iterator; + std::vector<T> m_handles; +}; // end class VectorHandle + + +class PointHandle : public Handle{ +public: + PointHandle(double x, double y) : pos(x,y) {} + PointHandle(Geom::Point pt) : pos(pt) {} + PointHandle() {} + Geom::Point pos; + void draw(cairo_t *cr, bool annotes = false) override; + + void* hit(Geom::Point mouse) override; + void move_to(void* hit, Geom::Point om, Geom::Point m) override; + void load(FILE* f) override; + void save(FILE* f) override; +}; + +class PointSetHandle : public Handle{ +public: + PointSetHandle() {} + std::vector<Geom::Point> pts; + void draw(cairo_t *cr, bool annotes = false) override; + + void* hit(Geom::Point mouse) override; + void move_to(void* hit, Geom::Point om, Geom::Point m) override; + void push_back(double x, double y) {pts.emplace_back(x,y);} + void push_back(Geom::Point pt) {pts.push_back(pt);} + unsigned size() {return pts.size();} + Geom::D2<Geom::SBasis> asBezier(); + void load(FILE* f) override; + void save(FILE* f) override; +}; + +class RectHandle : public Handle{ +public: + RectHandle() {} + RectHandle(Geom::Rect pos, bool show_center_handle) : pos(pos), show_center_handle(show_center_handle) {} + Geom::Rect pos; + bool show_center_handle; + void draw(cairo_t *cr, bool annotes = false) override; + + void* hit(Geom::Point mouse) override; + void move_to(void* hit, Geom::Point om, Geom::Point m) override; + void load(FILE* f) override; + void save(FILE* f) override; +}; + + +// used by Slider +inline std::string default_formatter(double x) +{ + std::ostringstream os; + os << x; + return os.str(); +} + +class Slider : public Handle +{ + public: + + typedef std::string (*formatter_t) (double ); + typedef double value_type; + + Slider() + : m_handle(), m_pos(Geom::Point(0,0)), m_length(1), + m_min(0), m_max(1), m_step(0), m_dir(Geom::X), + m_label(""), m_formatter(&default_formatter) + { + value(0); + } + + // pass step = 0 for having a continuos value variation + Slider( value_type _min, value_type _max, value_type _step, + value_type _value, std::string _label = "" ) + : m_handle(),m_pos(Geom::Point(0,0)), m_length(1), + m_min(_min), m_max(_max), m_step(_step), m_dir(Geom::X), + m_label(std::move(_label)), m_formatter(&default_formatter) + { + value(_value); + } + + void set( value_type _min, value_type _max, value_type _step, + value_type _value, const std::string& _label = "" ) + { + m_min = _min; + m_max = _max; + m_step = _step; + m_label = _label; + value(_value); + } + + value_type value() const; + + void value(value_type _value); + + value_type max_value() const + { + return m_max; + } + + void max_value(value_type _value); + + value_type min_value() const + { + return m_min; + } + + void min_value(value_type _value); + + // dir = X horizontal slider dir = Y vertical slider + void geometry(Geom::Point _pos, value_type _length, Geom::Dim2 _dir = Geom::X); + + void draw(cairo_t* cr, bool annotate = false) override; + + void formatter( formatter_t _formatter ) + { + m_formatter = _formatter; + } + + void* hit(Geom::Point pos) override + { + if (m_handle.hit(pos) != NULL) + return this; + return NULL; + } + + void move_to(void* hit, Geom::Point om, Geom::Point m) override; + + void load(FILE* f) override + { + m_handle.load(f); + } + + void save(FILE* f) override + { + m_handle.save(f); + } + + private: + PointHandle m_handle; + Geom::Point m_pos; + value_type m_length; + value_type m_min, m_max, m_step; + int m_dir; + std::string m_label; + formatter_t m_formatter; +}; + + + + + +class Toy { +public: + vector<Handle*> handles; + bool mouse_down = false; + Geom::Point old_mouse_point; + Handle* selected = nullptr; + void* hit_data = nullptr; + int canvas_click_button = 0; + double notify_offset = 0.0; + std::string name; + bool show_timings = false; + FILE* spool_file = nullptr; // if non-NULL we record all interactions to this file + + Toy() {} + + virtual ~Toy() {} + + virtual void draw(cairo_t *cr, std::ostringstream *notify, int w, int h, bool save, std::ostringstream *timing_stream); + + virtual void mouse_moved(GdkEventMotion* e); + virtual void mouse_pressed(GdkEventButton* e); + virtual void mouse_released(GdkEventButton* e); + virtual void canvas_click(Geom::Point at, int button); + virtual void scroll(GdkEventScroll* e); + + virtual void key_hit(GdkEventKey */*e*/) {} + + //Cheapo way of informing the framework what the toy would like drawn for it. + virtual bool should_draw_numbers() { return true; } + virtual int should_draw_bounds() { return 0; } + + virtual void first_time(int /*argc*/, char** /*argv*/) {} + + virtual void resize_canvas(Geom::Rect const & /*s*/) {} + virtual void load(FILE* f); + virtual void save(FILE* f); +}; + +//Framework Accesors +void redraw(); +void take_screenshot(const char* file); +void init(int argc, char **argv, Toy *t, int width=600, int height=600); + +void toggle_events(std::vector<Toggle> &ts, GdkEventButton* e); +void draw_toggles(cairo_t *cr, std::vector<Toggle> &ts); +Geom::Point read_point(FILE* f); + + + + + +const long long NS_PER_SECOND = 1000000000LL; +const long long NS_PER_NS = 1; + + +class Timer{ +public: + Timer() {} + // note that CPU time is tracked per-thread, so the timer is only useful + // in the thread it was start()ed from. + + class Time{ + public: + double value; + Time(long long /*s*/, long long l) : value(l) {} + Time(double v) : value(v) {} + Time operator/(double iters) const { + return Time(value / iters); + } + }; + + void start() { + nsec(start_time); + } + void lap(long long &ns) { + nsec(ns); + ns -= start_time; + } + Time lap() { + long long ns; + nsec(ns); + return Time(start_time, ns - start_time); + } + void nsec(long long &ns) { +#if ! (defined(_WIN32) || defined(__APPLE__)) + clock_gettime(clock, &ts); + ns = ts.tv_sec * NS_PER_SECOND + ts.tv_nsec / NS_PER_NS; +#else + ns = 0; +#endif + } + /** Ask the OS nicely for a big time slice */ + void ask_for_timeslice() { +#ifndef _WIN32 + sched_yield(); +#endif + } +private: + long long start_time; +#if ! (defined(_WIN32) || defined(__APPLE__)) + struct timespec ts; +# ifdef _POSIX_THREAD_CPUTIME + static const clockid_t clock = CLOCK_THREAD_CPUTIME_ID; +# else +# ifdef CLOCK_MONOTONIC + static const clockid_t clock = CLOCK_MONOTONIC; +# else + static const clockid_t clock = CLOCK_REALTIME; +# endif +# endif +#endif +}; + +inline std::ostream& operator<<(std::ostream& o, Timer::Time const &t) { + double tm = t.value; + unsigned prefix = 0; + char prefixes[] = "num kMGT"; + while(prefix < sizeof(prefixes) and tm > 1000) { + tm /= 1000.0; + prefix += 1; + } + o << tm << prefixes[prefix] << "s"; + return o; +} + + + +#endif // _2GEOM_TOY_FRAMEWORK2_H_ +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: + */ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4:fileencoding=utf-8:textwidth=99 : |