8#include <cairo-features.h>
9#if CAIRO_HAS_PDF_SURFACE
12#if CAIRO_HAS_SVG_SURFACE
31 return double(rand()) / RAND_MAX;
44 float a = V*S*cos(H)/3;
45 float b = V*S*sin(H)/3;
48 (k+2*
a)*inr - 2*
b*ing + (k-
a-
b)*inb,
49 (-k+
a+3*
b)*inr + (3*
a-
b)*ing + (-k+
a+2*
b)*inb,
50 (2*k-2*
a)*inr + 2*
b*ing + (2*k+
a+
b)*inb,
62 double v = (l <= 0.5) ? (l * (1.0 + sl)) : (l + sl - l * sl);
68 double fract, vsf, mid1, mid2;
124 PangoLayout* layout = pango_cairo_create_layout (cr);
125 pango_layout_set_text(layout, txt, -1);
127 pango_layout_set_font_description(layout, font_desc);
128 pango_font_description_free (font_desc);
129 PangoRectangle logical_extent;
130 pango_layout_get_pixel_extents(layout, NULL, &logical_extent);
132 pango_cairo_show_layout(cr, layout);
136 draw_text(cr, loc, txt.c_str(), bottom, fontdesc.c_str());
140 std::ostringstream number;
144 draw_text(cr, pos, number.str().c_str(), bottom);
148 std::ostringstream number;
152 draw_text(cr, pos, number.str().c_str(), bottom);
156 std::ostringstream number;
160 draw_text(cr, pos, number.str().c_str(), bottom);
170 cairo_set_line_width (cr, 0.5);
171 for(
unsigned i = 1; i < 4; i+=2) {
180 cairo_set_line_width (cr, 0.5);
187 cairo_set_line_width (cr, 1);
189 cairo_set_source_rgb (cr, handle->rgb[0], handle->rgb[1], handle->rgb[2]);
202 *notify << std::ends;
206 *timer_stream << std::ends;
213 if (modifiers & (GDK_BUTTON1_MASK | GDK_BUTTON3_MASK)) {
229 if (
auto hit = handle->hit(pos)) {
262 if (fscanf(f,
"%1023s",
data)) {
271 fprintf(f,
"%s\n",
name.c_str());
279 GtkWidget* about_window = gtk_window_new();
280 gtk_window_set_title(GTK_WINDOW(about_window),
"About");
281 gtk_window_set_resizable(GTK_WINDOW(about_window), FALSE);
283 GtkWidget* about_text = gtk_text_view_new();
284 GtkTextBuffer*
buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(about_text));
285 gtk_text_buffer_set_text(
buf,
"Toy lib2geom application", -1);
286 gtk_text_view_set_editable(GTK_TEXT_VIEW(about_text), FALSE);
287 gtk_window_set_child(GTK_WINDOW(about_window), about_text);
289 gtk_window_present(GTK_WINDOW(about_window));
292void quit(GSimpleAction *, GVariant *, gpointer) {
293 g_application_quit(g_application_get_default());
298 for(
unsigned i = 0; i < 2; i++)
299 assert(fscanf(f,
" %lf ", &p[i]));
305 using Closure = std::function<void (
char const *)>;
306 auto clipboard = gtk_widget_get_clipboard(
the_canvas);
307 auto closure =
new Closure(std::move(on_completion));
308 gdk_clipboard_read_text_async(clipboard,
nullptr, +[] (
GObject *source_object, GAsyncResult *res, gpointer
data) {
309 auto clipboard = GDK_CLIPBOARD(source_object);
310 auto closure =
reinterpret_cast<Closure *
>(
data);
311 auto str = gdk_clipboard_read_text_finish(clipboard, res,
nullptr);
312 closure->operator()(str);
321 assert(fscanf(f,
" %lf ", &a));
322 assert(fscanf(f,
" %lf ", &b));
329 auto d = GTK_FILE_DIALOG(source_object);
330 auto file = gtk_file_dialog_open_finish(d, res,
nullptr);
334 auto filename = g_file_get_path(file);
335 g_object_unref(file);
337 auto f = fopen(filename,
"r");
349 auto d = gtk_file_dialog_new();
350 gtk_file_dialog_set_title(d,
"Open handle configuration");
356 auto d = GTK_FILE_DIALOG(source_object);
357 auto file = gtk_file_dialog_save_finish(d, res,
nullptr);
361 auto filename = g_file_get_path(file);
362 g_object_unref(file);
364 auto f = fopen(filename,
"w");
374 auto d = gtk_file_dialog_new();
375 gtk_file_dialog_set_title(d,
"Save handle configuration");
385 bool save_png =
false;
387 unsigned l = strlen(filename);
388 if (l >= 4 && strcmp(filename + l - 4,
".png") == 0) {
389 s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
width,
height);
392#if CAIRO_HAS_PDF_SURFACE
393 else if (l >= 4 && strcmp(filename + l - 4,
".pdf") == 0) {
394 s = cairo_pdf_surface_create(filename,
width,
height);
397#if CAIRO_HAS_SVG_SURFACE
399 s = cairo_svg_surface_create(filename,
width,
height);
406 auto cr = cairo_create(s);
409 cairo_set_source_rgb(cr, 1, 1, 1);
414 std::ostringstream notify, timer_stream;
422 cairo_surface_write_to_png(s, filename);
425 cairo_surface_destroy(s);
430 auto d = GTK_FILE_DIALOG(source_object);
431 auto file = gtk_file_dialog_save_finish(d, res,
nullptr);
435 auto filename = g_file_get_path(file);
436 g_object_unref(file);
444 auto d = gtk_file_dialog_new();
445 gtk_file_dialog_set_title(d,
"Save file as svg, pdf or png");
450 GVariant *state = g_action_get_state(G_ACTION(action));
451 g_action_change_state(G_ACTION(action), g_variant_new_boolean(!g_variant_get_boolean(state)));
452 g_variant_unref(state);
457 g_simple_action_set_state(action, variant);
464 static std::optional<Geom::IntPoint> old_size;
465 if (
size != old_size) {
477 std::ostringstream notify, timer;
487static void mouse_motion_event(GtkEventControllerMotion *self,
double x,
double y, gpointer user_data)
491 gtk_event_controller_get_current_event_state(GTK_EVENT_CONTROLLER(self)));
495static void mouse_press_event(GtkGestureClick *self,
int n_press,
double x,
double y, gpointer user_data)
499 gtk_gesture_single_get_current_button(GTK_GESTURE_SINGLE(self)),
500 gtk_event_controller_get_current_event_state(GTK_EVENT_CONTROLLER(self)));
504static gboolean
scroll_event(GtkEventControllerScroll *self,
double dx,
double dy, gpointer user_data)
507 auto ev = gtk_event_controller_get_current_event(GTK_EVENT_CONTROLLER(self));
508 auto dir = gdk_scroll_event_get_direction(ev);
514static void mouse_release_event(GtkGestureClick *self,
int n_press,
double x,
double y, gpointer user_data)
518 gtk_gesture_single_get_current_button(GTK_GESTURE_SINGLE(self)),
519 gtk_event_controller_get_current_event_state(GTK_EVENT_CONTROLLER(self)));
523static gboolean
key_press_event(GtkEventControllerKey *self,
unsigned keyval,
unsigned keycode, GdkModifierType state, gpointer user_data)
532<?xml version="1.0" encoding="UTF-8"?>
536 <attribute name="label">File</attribute>
539 <attribute name="label">Open Handles</attribute>
540 <attribute name="action">app.open-handles</attribute>
543 <attribute name="label">Save Handles</attribute>
544 <attribute name="action">app.save-handles</attribute>
549 <attribute name="label">Save as PNG, SVG or PDF</attribute>
550 <attribute name="action">app.save-image</attribute>
555 <attribute name="label">Show Timings</attribute>
556 <attribute name="action">app.show-timings</attribute>
559 <attribute name="label">Quit</attribute>
560 <attribute name="action">app.quit</attribute>
565 <attribute name="label">Help</attribute>
567 <attribute name="label">About</attribute>
568 <attribute name="action">app.about</attribute>
577 {
"open-handles",
open_handles,
nullptr,
nullptr,
nullptr},
578 {
"save-handles",
save_handles,
nullptr,
nullptr,
nullptr},
579 {
"save-image",
save_cairo,
nullptr,
nullptr,
nullptr},
581 {
"quit",
quit,
nullptr,
nullptr,
nullptr},
587 "Load handle positions from given file",
"FILE"},
589 "Record all interaction to the given file",
"FILE"},
591 "Take screenshot and exit",
nullptr},
592 {G_OPTION_REMAINING, 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_FILENAME_ARRAY, &
arg_extra_files,
593 "Additional data files",
"FILES..."},
594 {
nullptr, 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE,
nullptr,
nullptr,
nullptr},
597static void activate(GApplication *app, gpointer);
598static void startup(GApplication *app, gpointer);
605 std::string app_name =
"org.inkscape.lib2geom.toy.";
606 char const *dir_pos = strrchr(argv[0], G_DIR_SEPARATOR);
607 std::string argv_name = dir_pos ? dir_pos + 1 : argv[0];
610 size_t dot_pos = argv_name.rfind(
'.');
611 if (dot_pos != std::string::npos) {
612 argv_name.erase(dot_pos);
615 app_name += argv_name;
617 GtkApplication* app = gtk_application_new(app_name.c_str(), G_APPLICATION_DEFAULT_FLAGS);
618 g_application_add_main_option_entries(G_APPLICATION(app),
the_options);
620 g_signal_connect(G_OBJECT(app),
"startup", G_CALLBACK(
startup),
nullptr);
621 g_signal_connect(G_OBJECT(app),
"activate", G_CALLBACK(
activate),
nullptr);
623 g_application_run(G_APPLICATION(app), argc, argv);
627static void startup(GApplication *app, gpointer) {
629 GMenuModel *menu = G_MENU_MODEL(gtk_builder_get_object(
builder,
"menu"));
630 gtk_application_set_menubar(GTK_APPLICATION(app), menu);
640 gchar
const **emulated_argv =
new gchar
const*[emulated_argc];
642 for (
int i = 1; i < emulated_argc; ++i) {
646 delete[] emulated_argv;
651 fclose(handles_file);
656 g_application_quit(app);
660 the_window = GTK_APPLICATION_WINDOW(gtk_application_window_new(GTK_APPLICATION(g_application_get_default())));
662 gtk_application_window_set_show_menubar(
the_window, TRUE);
667 auto scroll = gtk_event_controller_scroll_new(GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES);
668 g_signal_connect(scroll,
"scroll", G_CALLBACK(
scroll_event),
nullptr);
669 gtk_widget_add_controller(
the_canvas, scroll);
671 auto click = gtk_gesture_click_new();
672 gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(click), 0);
675 gtk_widget_add_controller(
the_canvas, GTK_EVENT_CONTROLLER(click));
677 auto motion = gtk_event_controller_motion_new();
679 gtk_widget_add_controller(
the_canvas, motion);
681 auto key = gtk_event_controller_key_new();
693 double rc, gc, bc, aa;
694 cairo_pattern_get_rgba(source, &
rc, &gc, &bc, &aa);
735 t.handle_click(pos, button);
740 for(
auto & t : ts) t.draw(cr);
749 int k = std::floor(v /
m_step);
762 _value = _value -
m_min;
763 int k = std::floor(_value /
m_step);
801 double rc, gc, bc, aa;
802 cairo_pattern_get_rgba(source, &
rc, &gc, &bc, &aa);
803 double lw = cairo_get_line_width(cr);
804 std::ostringstream os;
807 cairo_set_line_width(cr, 0.7);
811 cairo_set_line_width(cr, 0.4);
829 cairo_set_line_width(cr, lw);
836 m[fix_dir] =
m_pos[fix_dir];
871 fprintf(f,
"%lf %lf\n",
pos[0],
pos[1]);
875 for(
unsigned i = 0; i <
pts.size(); i++) {
882 for(
auto & pt :
pts) {
897 assert(1 == fscanf(f,
"%d\n", &n));
899 for(
int i = 0; i < n; i++) {
905 fprintf(f,
"%d\n", (
int)
pts.size());
906 for(
auto & pt :
pts) {
907 fprintf(f,
"%lf %lf\n", pt[0], pt[1]);
914 return handles_to_sbasis(
pts.begin(),
size()-1);
929 return (
void*)(intptr_t)1;
931 for(
int i = 0; i < 4; i++) {
933 return (
void*)(intptr_t)(2+i);
935 for(
int i = 0; i < 4; i++) {
938 return (
void*)(intptr_t)(6+i);
948 unsigned h = (unsigned)(uintptr_t)(
hit);
951 else if(h >= 2 and h <= 5) {
966 }
else if(h >= 6 and h <= 9) {
969 case 0: d = 1; side = 0;
break;
970 case 1: d = 0; side = 1;
break;
971 case 2: d = 1; side = 1;
break;
972 case 3: d = 0; side = 0;
break;
973 default: assert(
false);
984 assert(0 == fscanf(f,
"r\n"));
985 for(
int i = 0; i < 2; i++) {
993 for(
unsigned i = 0; i < 2; i++) {
994 fprintf(f,
"%lf %lf\n",
pos[i].min(),
pos[i].max());
_PangoFontDescription PangoFontDescription
Conversion between Bezier control points and SBasis curves.
struct _PangoLayout PangoLayout
Coord nearestTime(Point const &p, Coord from=0, Coord to=1) const override
Compute a time value at which the curve comes closest to a specified point.
Point pointAt(Coord t) const override
Evaluate the curve at a specified time value.
Adaptor that creates 2D functions from 1D ones.
constexpr void setEnds(C a, C b)
Set both ends of the interval simultaneously.
void setMin(CPoint const &p)
Set the upper left point of the rectangle.
bool contains(GenericRect< C > const &r) const
Check whether the rectangle includes all points in the given rectangle.
C top() const
Return top coordinate of the rectangle (+Y is downwards).
void setMax(CPoint const &p)
Set the lower right point of the rectangle.
CPoint midpoint() const
Get the point in the geometric center of the rectangle.
C left() const
Return leftmost coordinate of the rectangle (+X is to the right).
C height() const
Get the vertical extent of the rectangle.
C width() const
Get the horizontal extent of the rectangle.
CPoint corner(unsigned i) const
Return the n-th corner of the rectangle.
Two-dimensional point with integer coordinates.
Range of real numbers that is never empty.
Two-dimensional point that doubles as a vector.
virtual void move_to(void *hit, Geom::Point om, Geom::Point m)=0
virtual void draw(cairo_t *cr, bool annotes=false)=0
void draw(cairo_t *cr, bool annotes=false) override
void load(FILE *f) override
void move_to(void *hit, Geom::Point om, Geom::Point m) override
void save(FILE *f) override
void * hit(Geom::Point mouse) override
void load(FILE *f) override
void move_to(void *hit, Geom::Point om, Geom::Point m) override
void save(FILE *f) override
void draw(cairo_t *cr, bool annotes=false) override
void * hit(Geom::Point mouse) override
Geom::D2< Geom::SBasis > asBezier()
std::vector< Geom::Point > pts
void move_to(void *hit, Geom::Point om, Geom::Point m) override
void draw(cairo_t *cr, bool annotes=false) override
void load(FILE *f) override
void * hit(Geom::Point mouse) override
void save(FILE *f) override
value_type max_value() const
void draw(cairo_t *cr, bool annotate=false) override
value_type min_value() const
void * hit(Geom::Point pos) override
void geometry(Geom::Point _pos, value_type _length, Geom::Dim2 _dir=Geom::X)
void move_to(void *hit, Geom::Point om, Geom::Point m) override
void handle_click(Geom::Point const &pos, unsigned button)
void draw(cairo_t *cr, bool annotes=false) override
void * hit(Geom::Point pos) override
virtual void first_time(int, char **)
virtual void canvas_click(Geom::Point at, int button)
virtual void load(FILE *f)
virtual void mouse_pressed(Geom::Point const &pos, unsigned button, unsigned modifiers)
Geom::Point old_mouse_point
virtual int should_draw_bounds()
virtual void mouse_moved(Geom::Point const &pos, unsigned modifiers)
virtual bool should_draw_numbers()
vector< Handle * > handles
virtual void mouse_released(Geom::Point const &pos, unsigned button, unsigned modifiers)
virtual void save(FILE *f)
virtual void resize_canvas(Geom::Rect const &)
virtual void key_hit(unsigned keyval, unsigned modifiers)
virtual void draw(cairo_t *cr, std::ostringstream *notify, int w, int h, bool save, std::ostringstream *timing_stream)
virtual void scroll(GdkScrollDirection dir, Geom::Point const &delta)
_cairo_pattern cairo_pattern_t
struct _cairo_surface cairo_surface_t
Dim2
2D axis enumeration (X or Y).
double Coord
Floating point type used to store coordinates.
Angle distance(Angle const &a, Angle const &b)
static cairo_user_data_key_t key
void cairo_rectangle(cairo_t *cr, Geom::Rect const &r)
void cairo_line_to(cairo_t *cr, Geom::Point p1)
void draw_circ(cairo_t *cr, Geom::Point h)
void cairo_move_to(cairo_t *cr, Geom::Point p1)
static colour from_hsl(float H, float S, float L, float A)
static colour from_hsv(float H, float S, float V, float A)
static void mouse_motion_event(GtkEventControllerMotion *self, double x, double y, gpointer user_data)
static void mouse_press_event(GtkGestureClick *self, int n_press, double x, double y, gpointer user_data)
const char * the_builder_xml
static void mouse_release_event(GtkGestureClick *self, int n_press, double x, double y, gpointer user_data)
gchar ** the_emulated_argv
void save_cairo_cb(GObject *source_object, GAsyncResult *res, gpointer data)
gchar * arg_spool_filename
void write_image(char const *filename)
static void draw_callback(GtkDrawingArea *drawing_area, cairo_t *cr, int width, int height, gpointer user_data)
void open_handles_cb(GObject *source_object, GAsyncResult *res, gpointer data)
void init(int argc, char **argv, Toy *t, int width, int height)
void draw_number(cairo_t *cr, Geom::Point pos, int num, std::string name, bool bottom)
gchar * arg_screenshot_filename
gchar * arg_handles_filename
void toggle_events(std::vector< Toggle > &ts, Geom::Point const &pos, unsigned button)
static gboolean key_press_event(GtkEventControllerKey *self, unsigned keyval, unsigned keycode, GdkModifierType state, gpointer user_data)
Geom::Point read_point(FILE *f)
void cairo_set_source_rgba(cairo_t *cr, colour c)
static void activate(GApplication *app, gpointer)
void get_clipboard_text(std::function< void(char const *)> &&on_completion)
static GActionEntry the_actions[]
void open_handles(GSimpleAction *, GVariant *, gpointer)
static gboolean scroll_event(GtkEventControllerScroll *self, double dx, double dy, gpointer user_data)
void quit(GSimpleAction *, GVariant *, gpointer)
void save_handles_cb(GObject *source_object, GAsyncResult *res, gpointer data)
void show_about_dialog(GSimpleAction *, GVariant *, gpointer)
static void startup(GApplication *app, gpointer)
void save_cairo(GSimpleAction *, GVariant *, gpointer)
void draw_toggles(cairo_t *cr, std::vector< Toggle > &ts)
static void set_show_timings(GSimpleAction *action, GVariant *variant, gpointer)
GtkApplicationWindow * the_window
void save_handles(GSimpleAction *, GVariant *, gpointer)
static GtkWidget * the_canvas
static void toggle_action(GSimpleAction *action, GVariant *, gpointer)
static GOptionEntry const the_options[]
Geom::Interval read_interval(FILE *f)
void draw_text(cairo_t *cr, Geom::Point loc, const char *txt, bool bottom, const char *fontdesc)
void draw_text(cairo_t *cr, Geom::Point pos, const char *txt, bool bottom=false, const char *fontdesc="Sans")
Geom::Point read_point(FILE *f)
void cairo_set_source_rgba(cairo_t *cr, colour c)
void draw_number(cairo_t *cr, Geom::Point pos, int num, std::string name=std::string(), bool bottom=true)
Glib::RefPtr< Gtk::Builder > builder