2
* This is a plug-in for the GIMP.
4
* Generates clickable image maps.
6
* Copyright (C) 1998-2004 Maurits Rijk m.rijk@chello.nl
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or
11
* (at your option) any later version.
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software
20
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31
#include "imap_commands.h"
32
#include "imap_main.h"
33
#include "imap_misc.h"
34
#include "imap_object_popup.h"
35
#include "imap_polygon.h"
36
#include "imap_stock.h"
37
#include "imap_table.h"
39
#include "libgimp/stdplugins-intl.h"
41
#define MAX_POLYGON_POINTS 99
43
static gboolean polygon_is_valid(Object_t *obj);
44
static void polygon_destruct(Object_t *obj);
45
static Object_t *polygon_clone(Object_t *obj);
46
static void polygon_assign(Object_t *obj, Object_t *des);
47
static void polygon_draw(Object_t* obj, GdkWindow *window, GdkGC* gc);
48
static void polygon_draw_sashes(Object_t* obj, GdkWindow *window, GdkGC* gc);
49
static MoveSashFunc_t polygon_near_sash(Object_t *obj, gint x, gint y);
50
static gboolean polygon_point_is_on(Object_t *obj, gint x, gint y);
51
static void polygon_get_dimensions(Object_t *obj, gint *x, gint *y,
52
gint *width, gint *height);
53
static void polygon_resize(Object_t *obj, gint percentage_x,
55
static void polygon_move(Object_t *obj, gint dx, gint dy);
56
static gpointer polygon_create_info_widget(GtkWidget *frame);
57
static void polygon_update_info_widget(Object_t *obj, gpointer data);
58
static void polygon_fill_info_tab(Object_t *obj, gpointer data);
59
static void polygon_set_initial_focus(Object_t *obj, gpointer data);
60
static void polygon_update(Object_t* obj, gpointer data);
61
static void polygon_write_csim(Object_t* obj, gpointer param,
63
static void polygon_write_cern(Object_t* obj, gpointer param,
65
static void polygon_write_ncsa(Object_t* obj, gpointer param,
67
static void polygon_do_popup(Object_t *obj, GdkEventButton *event);
68
static const gchar* polygon_get_stock_icon_name(void);
70
static ObjectClass_t polygon_class = {
72
NULL, /* info_dialog */
80
NULL, /* polygon_normalize */
85
polygon_get_dimensions,
88
polygon_create_info_widget,
89
polygon_update_info_widget,
90
polygon_fill_info_tab,
91
polygon_set_initial_focus,
97
polygon_get_stock_icon_name
101
create_polygon(GList *points)
103
Polygon_t *polygon = g_new(Polygon_t, 1);
104
polygon->points = points;
105
return object_init(&polygon->obj, &polygon_class);
109
polygon_free_list(Polygon_t *polygon)
111
g_list_foreach(polygon->points, (GFunc) g_free, NULL);
112
g_list_free(polygon->points);
113
polygon->points = NULL;
117
polygon_destruct(Object_t *obj)
119
Polygon_t *polygon = ObjectToPolygon(obj);
120
polygon_free_list(polygon);
124
polygon_is_valid(Object_t *obj)
126
return g_list_length(ObjectToPolygon(obj)->points) > 2;
130
polygon_clone(Object_t *obj)
132
Polygon_t *polygon = ObjectToPolygon(obj);
133
Polygon_t *clone = g_new(Polygon_t, 1);
136
clone->points = NULL;
137
for (p = polygon->points; p; p = p->next) {
138
GdkPoint *point = (GdkPoint*) p->data;
139
polygon_append_point(clone, point->x, point->y);
145
polygon_assign(Object_t *obj, Object_t *des)
147
Polygon_t *src_polygon = ObjectToPolygon(obj);
148
Polygon_t *des_polygon = ObjectToPolygon(des);
151
polygon_free_list(des_polygon);
152
for (p = src_polygon->points; p; p = p->next) {
153
GdkPoint *point = (GdkPoint*) p->data;
154
polygon_append_point(des_polygon, point->x, point->y);
159
polygon_draw(Object_t *obj, GdkWindow *window, GdkGC *gc)
161
Polygon_t *polygon = ObjectToPolygon(obj);
162
draw_polygon(window, gc, polygon->points);
166
polygon_draw_sashes(Object_t *obj, GdkWindow *window, GdkGC *gc)
168
Polygon_t *polygon = ObjectToPolygon(obj);
170
for (p = polygon->points; p; p = p->next) {
171
GdkPoint *point = (GdkPoint*) p->data;
172
draw_sash(window, gc, point->x, point->y);
176
static GdkPoint *_sash_point;
177
static gint _sash_index;
180
move_sash(Object_t *obj, gint dx, gint dy)
182
_sash_point->x += dx;
183
_sash_point->y += dy;
186
static MoveSashFunc_t
187
polygon_near_sash(Object_t *obj, gint x, gint y)
189
Polygon_t *polygon = ObjectToPolygon(obj);
193
for (p = polygon->points; p; p = p->next, _sash_index++) {
194
GdkPoint *point = (GdkPoint*) p->data;
195
if (near_sash(point->x, point->y, x, y)) {
204
right_intersect(GdkPoint *p1, GdkPoint *p2, gint x, gint y)
206
gint dx = p2->x - p1->x;
207
gint dy = p2->y - p1->y;
209
if ((dy > 0 && y > p1->y && y < p2->y) ||
210
(dy < y && y > p2->y && y < p1->y)) {
211
gint sx = p1->x + (y - p1->y) * dx / dy;
218
polygon_point_is_on(Object_t *obj, gint x, gint y)
220
Polygon_t *polygon = ObjectToPolygon(obj);
223
GdkPoint *first, *prev;
226
first = prev = (GdkPoint*) p->data;
229
for (; p; p = p->next) {
230
GdkPoint *point = (GdkPoint*) p->data;
231
if (right_intersect(prev, point, x, y))
235
if (right_intersect(prev, first, x, y))
242
polygon_get_dimensions(Object_t *obj, gint *x, gint *y,
243
gint *width, gint *height)
245
Polygon_t *polygon = ObjectToPolygon(obj);
246
gint min_x = G_MAXINT, min_y = G_MAXINT;
247
gint max_x = G_MININT, max_y = G_MININT;
250
for (p = polygon->points; p; p = p->next) {
251
GdkPoint *point = (GdkPoint*) p->data;
252
if (point->x < min_x)
254
if (point->x > max_x)
256
if (point->y < min_y)
258
if (point->y > max_y)
263
*width = max_x - min_x;
264
*height = max_y - min_y;
268
polygon_resize(Object_t *obj, gint percentage_x, gint percentage_y)
270
Polygon_t *polygon = ObjectToPolygon(obj);
272
for (p = polygon->points; p; p = p->next) {
273
GdkPoint *point = (GdkPoint*) p->data;
274
point->x = point->x * percentage_x / 100;
275
point->y = point->y * percentage_y / 100;
280
polygon_move(Object_t *obj, gint dx, gint dy)
282
Polygon_t *polygon = ObjectToPolygon(obj);
284
for (p = polygon->points; p; p = p->next) {
285
GdkPoint *point = (GdkPoint*) p->data;
294
GtkTreeSelection *selection;
303
} PolygonProperties_t;
306
select_row_cb(GtkTreeSelection *selection, PolygonProperties_t *data)
311
if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
314
gtk_tree_model_get (model, &iter, 0, &point, -1);
318
gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->x), point->x);
319
gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->y), point->y);
324
update_button_clicked(GtkWidget *widget, PolygonProperties_t *data)
327
GtkTreeModel *model = GTK_TREE_MODEL(data->store);
329
if (gtk_tree_selection_get_selected (data->selection, &model, &iter)) {
331
gint x = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(data->x));
332
gint y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(data->y));
334
gtk_tree_model_get (model, &iter, 0, &point, -1);
337
gtk_list_store_set (data->store, &iter, 0, point, -1);
342
set_buttons_sensitivity(PolygonProperties_t *data)
344
gint rows = gtk_tree_model_iter_n_children (GTK_TREE_MODEL(data->store),
346
gtk_widget_set_sensitive(data->insert, rows != MAX_POLYGON_POINTS);
347
gtk_widget_set_sensitive(data->append, rows != MAX_POLYGON_POINTS);
348
gtk_widget_set_sensitive(data->remove, rows > 2);
352
insert_button_clicked(GtkWidget *widget, PolygonProperties_t *data)
355
GtkTreeModel *model = GTK_TREE_MODEL(data->store);
357
if (gtk_tree_selection_get_selected (data->selection, &model, &iter)) {
358
Polygon_t *polygon = ObjectToPolygon(data->obj);
361
gint x = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(data->x));
362
gint y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(data->y));
364
gtk_tree_model_get (model, &iter, 0, &point, -1);
365
here = g_list_find(polygon->points, point);
366
polygon->points = g_list_insert_before(polygon->points, here,
368
polygon_fill_info_tab(data->obj, data);
373
append_button_clicked(GtkWidget *widget, PolygonProperties_t *data)
375
gint x = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(data->x));
376
gint y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(data->y));
378
polygon_append_point(ObjectToPolygon(data->obj), x, y);
379
polygon_fill_info_tab(data->obj, data);
383
remove_button_clicked(GtkWidget *widget, PolygonProperties_t *data)
386
GtkTreeModel *model = GTK_TREE_MODEL(data->store);
388
if (gtk_tree_selection_get_selected (data->selection, &model, &iter)) {
389
Polygon_t *polygon = ObjectToPolygon(data->obj);
392
gtk_tree_model_get (model, &iter, 0, &point, -1);
393
polygon->points = g_list_remove(polygon->points, point);
396
polygon_fill_info_tab(data->obj, data);
401
x_changed_cb(GtkWidget *widget, gpointer data)
403
Object_t *obj = ((PolygonProperties_t*) data)->obj;
404
gint x = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
406
edit_area_info_dialog_emit_geometry_signal(obj->class->info_dialog);
410
y_changed_cb(GtkWidget *widget, gpointer data)
412
Object_t *obj = ((PolygonProperties_t*) data)->obj;
413
gint y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
415
edit_area_info_dialog_emit_geometry_signal(obj->class->info_dialog);
419
render_x(GtkTreeViewColumn *column, GtkCellRenderer *cell,
420
GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
425
gtk_tree_model_get(tree_model, iter, 0, &point, -1);
426
sprintf(scratch, "%d", point->x);
427
g_object_set(cell, "text", scratch, "xalign", 1.0, NULL);
431
render_y(GtkTreeViewColumn *column, GtkCellRenderer *cell,
432
GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
437
gtk_tree_model_get(tree_model, iter, 0, &point, -1);
438
sprintf(scratch, "%d", point->y);
439
g_object_set(cell, "text", scratch, "xalign", 1.0, NULL);
443
polygon_create_info_widget(GtkWidget *frame)
445
PolygonProperties_t *props = g_new(PolygonProperties_t, 1);
446
GtkWidget *hbox, *swin, *table, *label;
448
gint max_width = get_image_width();
449
gint max_height = get_image_height();
450
GtkCellRenderer *renderer;
451
GtkTreeViewColumn *column;
453
hbox = gtk_hbox_new(FALSE, 12);
454
gtk_container_add(GTK_CONTAINER(frame), hbox);
455
gtk_widget_show(hbox);
457
swin = gtk_scrolled_window_new(NULL, NULL);
459
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin),
460
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
461
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(swin),
463
gtk_box_pack_start(GTK_BOX(hbox), swin, FALSE, FALSE, FALSE);
464
gtk_widget_show(swin);
466
props->store = gtk_list_store_new (1, G_TYPE_POINTER);
467
view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (props->store));
468
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
469
g_object_unref (props->store);
470
gtk_widget_show (view);
472
renderer = gtk_cell_renderer_text_new ();
473
column = gtk_tree_view_column_new_with_attributes (_("x (pixels)"),
476
gtk_tree_view_column_set_cell_data_func(column, renderer,
477
render_x, props, NULL);
478
gtk_tree_view_column_set_alignment(column, 0.5);
479
gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
481
renderer = gtk_cell_renderer_text_new ();
482
column = gtk_tree_view_column_new_with_attributes (_("y (pixels)"),
485
gtk_tree_view_column_set_cell_data_func(column, renderer,
486
render_y, props, NULL);
487
gtk_tree_view_column_set_alignment(column, 0.5);
488
gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
490
gtk_container_add (GTK_CONTAINER (swin), view);
492
table = gtk_table_new(6, 3, FALSE);
493
gtk_table_set_row_spacings(GTK_TABLE(table), 6);
494
gtk_table_set_col_spacings(GTK_TABLE(table), 6);
495
gtk_box_pack_start(GTK_BOX(hbox), table, FALSE, FALSE, FALSE);
496
gtk_widget_show(table);
498
label = create_label_in_table(table, 0, 0, "_x:");
499
props->x = create_spin_button_in_table(table, label, 0, 1, 1, 0,
501
g_signal_connect(props->x, "changed",
502
G_CALLBACK(x_changed_cb), (gpointer) props);
503
gtk_widget_set_size_request(props->x, 64, -1);
504
create_label_in_table(table, 0, 2, _("pixels"));
506
label = create_label_in_table(table, 1, 0, "_y:");
507
props->y = create_spin_button_in_table(table, label, 1, 1, 1, 0,
509
g_signal_connect(props->y, "changed",
510
G_CALLBACK(y_changed_cb), (gpointer) props);
511
gtk_widget_set_size_request(props->y, 64, -1);
512
create_label_in_table(table, 1, 2, _("pixels"));
514
props->update = gtk_button_new_with_mnemonic(_("_Update"));
515
g_signal_connect(props->update, "clicked",
516
G_CALLBACK(update_button_clicked), props);
517
gtk_table_attach_defaults(GTK_TABLE(table), props->update, 1, 2, 2, 3);
518
gtk_widget_show(props->update);
520
props->insert = gtk_button_new_with_mnemonic(_("_Insert"));
521
g_signal_connect(props->insert, "clicked",
522
G_CALLBACK(insert_button_clicked), props);
523
gtk_table_attach_defaults(GTK_TABLE(table), props->insert, 1, 2, 3, 4);
524
gtk_widget_show(props->insert);
526
props->append = gtk_button_new_with_mnemonic(_("A_ppend"));
527
g_signal_connect(props->append, "clicked",
528
G_CALLBACK(append_button_clicked), props);
529
gtk_table_attach_defaults(GTK_TABLE(table), props->append, 1, 2, 4, 5);
530
gtk_widget_show(props->append);
532
props->remove = gtk_button_new_with_mnemonic(_("_Remove"));
533
g_signal_connect(props->remove, "clicked",
534
G_CALLBACK(remove_button_clicked), props);
535
gtk_table_attach_defaults(GTK_TABLE(table), props->remove, 1, 2, 5, 6);
536
gtk_widget_show(props->remove);
540
props->selection = gtk_tree_view_get_selection(GTK_TREE_VIEW (view));
541
gtk_tree_selection_set_mode(props->selection, GTK_SELECTION_SINGLE);
542
g_signal_connect (props->selection, "changed",
543
G_CALLBACK (select_row_cb), props);
549
update_timeout(gpointer data)
551
PolygonProperties_t *props = (PolygonProperties_t*) data;
552
polygon_fill_info_tab(props->obj, data);
557
polygon_update_info_widget(Object_t *obj, gpointer data)
559
PolygonProperties_t *props = (PolygonProperties_t*) data;
562
gtk_spin_button_set_value(GTK_SPIN_BUTTON(props->x), _sash_point->x);
563
gtk_spin_button_set_value(GTK_SPIN_BUTTON(props->y), _sash_point->y);
565
if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(props->store), &iter,
566
NULL, _sash_index)) {
567
gtk_tree_selection_select_iter(props->selection, &iter);
571
g_source_remove(props->timeout);
572
props->timeout = g_timeout_add(1000, update_timeout, data);
576
polygon_fill_info_tab(Object_t *obj, gpointer data)
578
Polygon_t *polygon = ObjectToPolygon(obj);
579
PolygonProperties_t *props = (PolygonProperties_t*) data;
585
gtk_list_store_clear(props->store);
587
for (p = polygon->points; p; p = p->next) {
588
gtk_list_store_append(props->store, &iter);
589
gtk_list_store_set(props->store, &iter, 0, p->data, -1);
592
if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(props->store), &iter,
593
NULL, _sash_index)) {
594
gtk_tree_selection_select_iter(props->selection, &iter);
596
set_buttons_sensitivity(props);
600
polygon_set_initial_focus(Object_t *obj, gpointer data)
602
PolygonProperties_t *props = (PolygonProperties_t*) data;
603
gtk_widget_grab_focus(props->x);
607
polygon_update(Object_t* obj, gpointer data)
609
/* Nothing to be done! */
613
polygon_write_csim(Object_t *obj, gpointer param, OutputFunc_t output)
615
Polygon_t *polygon = ObjectToPolygon(obj);
618
output(param, "\"poly\" coords=\"");
619
for (p = polygon->points; p; p = p->next) {
620
GdkPoint *point = (GdkPoint*) p->data;
621
output(param, "%d,%d", point->x, point->y);
622
output(param, "%c", (p->next) ? ',' : '"');
627
polygon_write_cern(Object_t *obj, gpointer param, OutputFunc_t output)
629
Polygon_t *polygon = ObjectToPolygon(obj);
631
GdkPoint *first = (GdkPoint*) polygon->points->data;
633
output(param, "poly ");
634
for (p = polygon->points; p; p = p->next) {
635
GdkPoint *point = (GdkPoint*) p->data;
636
output(param, "(%d,%d) ", point->x, point->y);
638
output(param, "(%d,%d)", first->x, first->y);
642
polygon_write_ncsa(Object_t *obj, gpointer param, OutputFunc_t output)
644
Polygon_t *polygon = ObjectToPolygon(obj);
646
GdkPoint *first = (GdkPoint*) polygon->points->data;
648
output(param, "poly %s", obj->url);
649
for (p = polygon->points; p; p = p->next) {
650
GdkPoint *point = (GdkPoint*) p->data;
651
output(param, " %d,%d", point->x, point->y);
653
output(param, " %d,%d", first->x, first->y);
656
static gboolean _insert_edge;
657
static gint _insert_x;
658
static gint _insert_y;
661
polygon_insert_point(GtkWidget *widget, gpointer data)
663
Command_t *command = insert_point_command_new(get_popup_object(), _insert_x,
664
_insert_y, _insert_edge);
665
command_execute(command);
669
polygon_delete_point(GtkWidget *widget, gpointer data)
671
Command_t *command = delete_point_command_new(get_popup_object(),
673
command_execute(command);
677
point_near_edge(GdkPoint *first, GdkPoint *second, gint x, gint y)
682
den = (first->x - x) * (first->x - second->x) +
683
(first->y - y) * (first->y - second->y);
684
nom = (second->x - first->x) * (second->x - first->x) +
685
(second->y - first->y) * (second->y - first->y);
686
u = (gdouble) den / nom;
687
if (u >= 0.0 && u <= 1.0) {
688
gint sx = first->x + (gint) (u * (second->x - first->x)) - x;
689
gint sy = first->y + (gint) (u * (second->y - first->y)) - y;
690
return sx * sx + sy * sy <= 25; /* Fix me! */
696
polygon_near_edge(Object_t *obj, gint x, gint y)
698
Polygon_t *polygon = ObjectToPolygon(obj);
699
GList *p = polygon->points;
700
GdkPoint *first = (GdkPoint*) p->data;
701
GdkPoint *prev = first;
704
for (p = p->next; p; p = p->next, n++) {
705
GdkPoint *next = (GdkPoint*) p->data;
706
if (point_near_edge(prev, next, x, y))
710
return (point_near_edge(prev, first, x, y)) ? n + 1 : 0;
714
polygon_do_popup(Object_t *obj, GdkEventButton *event)
716
gint x = get_real_coord((gint) event->x);
717
gint y = get_real_coord((gint) event->y);
719
if (polygon_near_sash(obj, x, y)) {
720
static ObjectPopup_t *delete_popup;
722
delete_popup = make_object_popup();
723
object_popup_prepend_menu(delete_popup, _("Delete Point"),
724
polygon_delete_point, delete_popup);
726
object_handle_popup(delete_popup, obj, event);
728
_insert_edge = polygon_near_edge(obj, x, y);
730
static ObjectPopup_t *insert_popup;
736
insert_popup = make_object_popup();
737
object_popup_prepend_menu(insert_popup, _("Insert Point"),
738
polygon_insert_point, insert_popup);
740
object_handle_popup(insert_popup, obj, event);
742
object_do_popup(obj, event);
748
polygon_get_stock_icon_name(void)
750
return IMAP_STOCK_POLYGON;
753
static GList *_prev_link;
756
polygon_factory_finish(Object_t *obj, gint x, gint y)
758
Polygon_t *polygon = ObjectToPolygon(obj);
759
GdkPoint *prev_point = (GdkPoint*) _prev_link->data;
761
if (x == prev_point->x && y == prev_point->y) {
762
polygon_remove_last_point(polygon);
765
polygon_append_point(polygon, x, y);
766
_prev_link = _prev_link->next;
772
polygon_factory_cancel(GdkEventButton *event, Object_t *obj)
774
if (event->state & GDK_SHIFT_MASK) {
777
Polygon_t *polygon = ObjectToPolygon(obj);
778
GList *link = _prev_link;
780
_prev_link = _prev_link->prev;
781
g_free((GdkPoint*) link->data);
782
polygon->points = g_list_remove_link(polygon->points, link);
784
return _prev_link == NULL;
788
polygon_factory_create_object(gint x, gint y)
792
points = _prev_link = g_list_append(NULL, new_point(x, y));
793
points = g_list_append(points, new_point(x, y));
795
return create_polygon(points);
799
polygon_factory_set_xy(Object_t *obj, guint state, gint x, gint y)
801
Polygon_t *polygon = ObjectToPolygon(obj);
802
GList *last = g_list_last(polygon->points);
803
GdkPoint *point = (GdkPoint*) last->data;
804
GdkPoint *prev = (GdkPoint*) last->prev->data;
809
main_set_dimension(x - prev->x, y - prev->y);
812
static ObjectFactory_t polygon_factory = {
813
NULL, /* Object pointer */
814
polygon_factory_finish,
815
polygon_factory_cancel,
816
polygon_factory_create_object,
817
polygon_factory_set_xy
821
get_polygon_factory(guint state)
823
return &polygon_factory;
827
polygon_remove_last_point(Polygon_t *polygon)
829
GList *last = g_list_last(polygon->points);
830
g_free((GdkPoint*) last->data);
831
polygon->points = g_list_remove_link(polygon->points, last);
835
new_point(gint x, gint y)
837
GdkPoint *point = g_new(GdkPoint, 1);
844
polygon_append_point(Polygon_t *polygon, gint x, gint y)
846
polygon->points = g_list_append(polygon->points, new_point(x, y));