1 /*
2 * This is a plug-in for GIMP.
3 *
4 * Generates clickable image maps.
5 *
6 * Copyright (C) 1998-2005 Maurits Rijk m.rijk@chello.nl
7 *
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 3 of the License, or
11 * (at your option) any later version.
12 *
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.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 *
21 */
22
23 #include "config.h"
24
25 #include <gtk/gtk.h>
26
27 #include "imap_commands.h"
28 #include "imap_default_dialog.h"
29 #include "imap_grid.h"
30 #include "imap_main.h"
31 #include "imap_object.h"
32 #include "imap_string.h"
33
34 typedef struct {
35 ObjectListCallbackFunc_t func;
36 gpointer data;
37 } ObjectListCB_t;
38
39 static ObjectList_t *_paste_buffer;
40
41 static gpointer
object_list_callback_add(ObjectListCallback_t * list,ObjectListCallbackFunc_t func,gpointer data)42 object_list_callback_add(ObjectListCallback_t *list,
43 ObjectListCallbackFunc_t func, gpointer data)
44 {
45 ObjectListCB_t *cb = g_new(ObjectListCB_t, 1);
46 cb->func = func;
47 cb->data = data;
48 list->list = g_list_append(list->list, cb);
49 return cb;
50 }
51
52 static void
object_list_callback_remove(ObjectListCallback_t * list,gpointer id)53 object_list_callback_remove(ObjectListCallback_t *list, gpointer id)
54 {
55 list->list = g_list_remove(list->list, id);
56 }
57
58 static void
object_list_callback_call(ObjectListCallback_t * list,Object_t * obj)59 object_list_callback_call(ObjectListCallback_t *list, Object_t *obj)
60 {
61 GList *p;
62 for (p = list->list; p; p = p->next) {
63 ObjectListCB_t *cb = (ObjectListCB_t*) p->data;
64 cb->func(obj, cb->data);
65 }
66 }
67
68 gpointer
object_list_add_changed_cb(ObjectList_t * list,ObjectListCallbackFunc_t func,gpointer data)69 object_list_add_changed_cb(ObjectList_t *list, ObjectListCallbackFunc_t func,
70 gpointer data)
71 {
72 return object_list_callback_add(&list->changed_cb, func, data);
73 }
74
75 gpointer
object_list_add_update_cb(ObjectList_t * list,ObjectListCallbackFunc_t func,gpointer data)76 object_list_add_update_cb(ObjectList_t *list, ObjectListCallbackFunc_t func,
77 gpointer data)
78 {
79 return object_list_callback_add(&list->update_cb, func, data);
80 }
81
82 gpointer
object_list_add_add_cb(ObjectList_t * list,ObjectListCallbackFunc_t func,gpointer data)83 object_list_add_add_cb(ObjectList_t *list, ObjectListCallbackFunc_t func,
84 gpointer data)
85 {
86 return object_list_callback_add(&list->add_cb, func, data);
87 }
88
89 gpointer
object_list_add_remove_cb(ObjectList_t * list,ObjectListCallbackFunc_t func,gpointer data)90 object_list_add_remove_cb(ObjectList_t *list, ObjectListCallbackFunc_t func,
91 gpointer data)
92 {
93 return object_list_callback_add(&list->remove_cb, func, data);
94 }
95
96 gpointer
object_list_add_select_cb(ObjectList_t * list,ObjectListCallbackFunc_t func,gpointer data)97 object_list_add_select_cb(ObjectList_t *list, ObjectListCallbackFunc_t func,
98 gpointer data)
99 {
100 return object_list_callback_add(&list->select_cb, func, data);
101 }
102
103 gpointer
object_list_add_move_cb(ObjectList_t * list,ObjectListCallbackFunc_t func,gpointer data)104 object_list_add_move_cb(ObjectList_t *list, ObjectListCallbackFunc_t func,
105 gpointer data)
106 {
107 return object_list_callback_add(&list->move_cb, func, data);
108 }
109
110 gpointer
object_list_add_geometry_cb(ObjectList_t * list,ObjectListCallbackFunc_t func,gpointer data)111 object_list_add_geometry_cb(ObjectList_t *list, ObjectListCallbackFunc_t func,
112 gpointer data)
113 {
114 return object_list_callback_add(&list->geometry_cb, func, data);
115 }
116
117 gpointer
paste_buffer_add_add_cb(ObjectListCallbackFunc_t func,gpointer data)118 paste_buffer_add_add_cb(ObjectListCallbackFunc_t func, gpointer data)
119 {
120 if (!_paste_buffer)
121 _paste_buffer = make_object_list();
122 return object_list_callback_add(&_paste_buffer->add_cb, func, data);
123 }
124
125 gpointer
paste_buffer_add_remove_cb(ObjectListCallbackFunc_t func,gpointer data)126 paste_buffer_add_remove_cb(ObjectListCallbackFunc_t func, gpointer data)
127 {
128 if (!_paste_buffer)
129 _paste_buffer = make_object_list();
130 return object_list_callback_add(&_paste_buffer->remove_cb, func, data);
131 }
132
133 void
object_list_remove_add_cb(ObjectList_t * list,gpointer id)134 object_list_remove_add_cb(ObjectList_t *list, gpointer id)
135 {
136 object_list_callback_remove(&list->add_cb, id);
137 }
138
139 void
object_list_remove_select_cb(ObjectList_t * list,gpointer id)140 object_list_remove_select_cb(ObjectList_t *list, gpointer id)
141 {
142 object_list_callback_remove(&list->select_cb, id);
143 }
144
145 void
object_list_remove_remove_cb(ObjectList_t * list,gpointer id)146 object_list_remove_remove_cb(ObjectList_t *list, gpointer id)
147 {
148 object_list_callback_remove(&list->remove_cb, id);
149 }
150
151 void
object_list_remove_move_cb(ObjectList_t * list,gpointer id)152 object_list_remove_move_cb(ObjectList_t *list, gpointer id)
153 {
154 object_list_callback_remove(&list->move_cb, id);
155 }
156
157 void
object_list_remove_geometry_cb(ObjectList_t * list,gpointer id)158 object_list_remove_geometry_cb(ObjectList_t *list, gpointer id)
159 {
160 object_list_callback_remove(&list->geometry_cb, id);
161 }
162
163 Object_t*
object_init(Object_t * obj,ObjectClass_t * class)164 object_init(Object_t *obj, ObjectClass_t *class)
165 {
166 obj->class = class;
167 obj->refcount = 1;
168 obj->selected = FALSE;
169 obj->locked = FALSE;
170 obj->url = g_strdup("");
171 obj->target = g_strdup("");
172 obj->comment = g_strdup("");
173 obj->mouse_over = g_strdup("");
174 obj->mouse_out = g_strdup("");
175 obj->focus = g_strdup("");
176 obj->blur = g_strdup("");
177 return obj;
178 }
179
180 static void
object_destruct(Object_t * obj)181 object_destruct(Object_t *obj)
182 {
183 if (obj->class->destruct)
184 obj->class->destruct(obj);
185 g_free(obj->url);
186 g_free(obj->target);
187 g_free(obj->comment);
188 g_free(obj->mouse_over);
189 g_free(obj->mouse_out);
190 g_free(obj->focus);
191 g_free(obj->blur);
192 g_free(obj);
193 }
194
195 Object_t*
object_ref(Object_t * obj)196 object_ref(Object_t *obj)
197 {
198 obj->refcount++;
199 return obj;
200 }
201
202 void
object_unref(Object_t * obj)203 object_unref(Object_t *obj)
204 {
205 if (!--obj->refcount)
206 object_destruct(obj);
207 }
208
209 Object_t*
object_clone(Object_t * obj)210 object_clone(Object_t *obj)
211 {
212 Object_t *clone = obj->class->clone(obj);
213 clone->class = obj->class;
214 clone->refcount = 1;
215 clone->selected = obj->selected;
216 clone->locked = FALSE;
217 clone->url = g_strdup(obj->url);
218 clone->target = g_strdup(obj->target);
219 clone->comment = g_strdup(obj->comment);
220 clone->mouse_over = g_strdup(obj->mouse_over);
221 clone->mouse_out = g_strdup(obj->mouse_out);
222 clone->focus = g_strdup(obj->focus);
223 clone->blur = g_strdup(obj->blur);
224 return clone;
225 }
226
227 static Object_t*
object_copy(Object_t * src,Object_t * des)228 object_copy(Object_t *src, Object_t *des)
229 {
230 des->class = src->class;
231 des->selected = src->selected;
232 des->locked = FALSE;
233 g_strreplace(&des->url, src->url);
234 g_strreplace(&des->target, src->target);
235 g_strreplace(&des->comment, src->comment);
236 g_strreplace(&des->mouse_over, src->mouse_over);
237 g_strreplace(&des->mouse_out, src->mouse_out);
238 g_strreplace(&des->focus, src->focus);
239 g_strreplace(&des->blur, src->blur);
240 return des;
241 }
242
243 Object_t*
object_assign(Object_t * obj,Object_t * des)244 object_assign(Object_t *obj, Object_t *des)
245 {
246 obj->class->assign(obj, des);
247 return object_copy(obj, des);
248 }
249
250 void
object_draw(Object_t * obj,cairo_t * cr)251 object_draw(Object_t *obj, cairo_t *cr)
252 {
253 PreferencesData_t *preferences = get_preferences();
254 ColorSelData_t *colors = &preferences->colors;
255 GdkColor *fg, *bg;
256 gdouble dash = 4.;
257
258 if (obj->selected & 4) {
259 fg = &colors->interactive_fg;
260 bg = &colors->interactive_bg;
261 obj->selected &= ~4;
262 } else if (obj->selected) {
263 fg = &colors->selected_fg;
264 bg = &colors->selected_bg;
265 } else {
266 fg = &colors->normal_fg;
267 bg = &colors->normal_bg;
268 }
269
270 cairo_save (cr);
271 gdk_cairo_set_source_color (cr, bg);
272 obj->class->draw(obj, cr);
273 gdk_cairo_set_source_color (cr, fg);
274 cairo_set_dash (cr, &dash, 1, 0.);
275 obj->class->draw(obj, cr);
276
277 if (obj->selected && preferences->show_area_handle)
278 obj->class->draw_sashes(obj, cr);
279 cairo_restore (cr);
280 }
281
282 void
object_edit(Object_t * obj,gboolean add)283 object_edit(Object_t *obj, gboolean add)
284 {
285 if (!obj->class->info_dialog)
286 obj->class->info_dialog = create_edit_area_info_dialog(obj);
287 edit_area_info_dialog_show(obj->class->info_dialog, obj, add);
288 }
289
290 void
object_select(Object_t * obj)291 object_select(Object_t *obj)
292 {
293 obj->selected = TRUE;
294 object_list_callback_call(&obj->list->select_cb, obj);
295 object_emit_geometry_signal(obj);
296 }
297
298 void
object_unselect(Object_t * obj)299 object_unselect(Object_t *obj)
300 {
301 obj->selected = FALSE;
302 object_list_callback_call(&obj->list->select_cb, obj);
303 object_emit_geometry_signal(obj);
304 }
305
306 void
object_move(Object_t * obj,gint dx,gint dy)307 object_move(Object_t *obj, gint dx, gint dy)
308 {
309 obj->class->move(obj, dx, dy);
310 object_emit_geometry_signal(obj);
311 }
312
313 void
object_move_sash(Object_t * obj,gint dx,gint dy)314 object_move_sash(Object_t *obj, gint dx, gint dy)
315 {
316 gint x, y, width, height;
317 MoveSashFunc_t sash_func;
318
319 obj->class->get_dimensions(obj, &x, &y, &width, &height);
320 if (dx == 0)
321 x += (width / 2);
322 else
323 x += width;
324
325 if (dy == 0)
326 y += (height / 2);
327 else
328 y += height;
329
330 sash_func = obj->class->near_sash(obj, x, y);
331
332 if (sash_func) {
333 sash_func(obj, dx, dy);
334 object_emit_geometry_signal(obj);
335 }
336 }
337
338 void
object_remove(Object_t * obj)339 object_remove(Object_t *obj)
340 {
341 object_list_remove(obj->list, obj);
342 object_emit_geometry_signal(obj);
343 }
344
345 void
object_lock(Object_t * obj)346 object_lock(Object_t *obj)
347 {
348 obj->locked = TRUE;
349 }
350
351 void
object_unlock(Object_t * obj)352 object_unlock(Object_t *obj)
353 {
354 obj->locked = FALSE;
355 }
356
357 void
object_set_url(Object_t * obj,const gchar * url)358 object_set_url(Object_t *obj, const gchar *url)
359 {
360 g_strreplace(&obj->url, url);
361 }
362
363 void
object_set_target(Object_t * obj,const gchar * target)364 object_set_target(Object_t *obj, const gchar *target)
365 {
366 g_strreplace(&obj->target, target);
367 }
368
369 void
object_set_comment(Object_t * obj,const gchar * comment)370 object_set_comment(Object_t *obj, const gchar *comment)
371 {
372 g_strreplace(&obj->comment, comment);
373 }
374
375 void
object_set_mouse_over(Object_t * obj,const gchar * mouse_over)376 object_set_mouse_over(Object_t *obj, const gchar *mouse_over)
377 {
378 g_strreplace(&obj->mouse_over, mouse_over);
379 }
380
381 void
object_set_mouse_out(Object_t * obj,const gchar * mouse_out)382 object_set_mouse_out(Object_t *obj, const gchar *mouse_out)
383 {
384 g_strreplace(&obj->mouse_out, mouse_out);
385 }
386
387 void
object_set_focus(Object_t * obj,const gchar * focus)388 object_set_focus(Object_t *obj, const gchar *focus)
389 {
390 g_strreplace(&obj->focus, focus);
391 }
392
393 void
object_set_blur(Object_t * obj,const gchar * blur)394 object_set_blur(Object_t *obj, const gchar *blur)
395 {
396 g_strreplace(&obj->blur, blur);
397 }
398
399 gint
object_get_position_in_list(Object_t * obj)400 object_get_position_in_list(Object_t *obj)
401 {
402 return g_list_index(obj->list->list, (gpointer) obj);
403 }
404
405 void
object_emit_changed_signal(Object_t * obj)406 object_emit_changed_signal(Object_t *obj)
407 {
408 object_list_callback_call(&obj->list->changed_cb, obj);
409 }
410
411 void
object_emit_geometry_signal(Object_t * obj)412 object_emit_geometry_signal(Object_t *obj)
413 {
414 object_list_callback_call(&obj->list->geometry_cb, obj);
415 }
416
417 void
object_emit_update_signal(Object_t * obj)418 object_emit_update_signal(Object_t *obj)
419 {
420 object_list_callback_call(&obj->list->update_cb, obj);
421 }
422
423 void
do_object_locked_dialog(void)424 do_object_locked_dialog(void)
425 {
426 static DefaultDialog_t *dialog;
427 if (!dialog) {
428 dialog = make_default_dialog("Object locked");
429 default_dialog_hide_cancel_button(dialog);
430 default_dialog_hide_apply_button(dialog);
431 default_dialog_set_label(
432 dialog,
433 "\n You cannot delete the selected object \n"
434 "since it is currently being edited.\n");
435 }
436 default_dialog_show(dialog);
437 }
438
439 static Object_t*
object_factory_create_object(ObjectFactory_t * factory,gint x,gint y)440 object_factory_create_object(ObjectFactory_t *factory, gint x, gint y)
441 {
442 return factory->obj = factory->create_object(x, y);
443 }
444
445 static gboolean
button_motion(GtkWidget * widget,GdkEventMotion * event,ObjectFactory_t * factory)446 button_motion(GtkWidget *widget, GdkEventMotion *event,
447 ObjectFactory_t *factory)
448 {
449 gint x = get_real_coord((gint) event->x);
450 gint y = get_real_coord((gint) event->y);
451
452 round_to_grid(&x, &y);
453
454 factory->set_xy(factory->obj, event->state, x, y);
455
456 preview_redraw ();
457
458 return FALSE;
459 }
460
461 gboolean
object_on_button_press(GtkWidget * widget,GdkEventButton * event,gpointer data)462 object_on_button_press(GtkWidget *widget, GdkEventButton *event, gpointer data)
463 {
464 static ObjectFactory_t *factory;
465 PreferencesData_t *preferences = get_preferences();
466 gint x = get_real_coord((gint) event->x);
467 gint y = get_real_coord((gint) event->y);
468 static Object_t *obj;
469
470 if (event->type == GDK_2BUTTON_PRESS)
471 return FALSE;
472 round_to_grid(&x, &y);
473
474 if (obj) {
475 if (event->button == 1) {
476 if (!factory->finish || factory->finish(obj, x, y)) {
477 g_signal_handlers_disconnect_by_func(widget,
478 button_motion,
479 factory);
480 if (object_is_valid(obj)) {
481 Command_t *command = create_command_new(get_shapes(), obj);
482 command_execute(command);
483 if (preferences->prompt_for_area_info)
484 object_edit(obj, FALSE);
485 } else {
486 object_unref(obj);
487 }
488 preview_unset_tmp_obj (obj);
489 preview_redraw ();
490 obj = NULL;
491 main_clear_dimension();
492 }
493 } else if (event->button == 3) {
494 if (!factory->cancel || factory->cancel(event, obj)) {
495 g_signal_handlers_disconnect_by_func(widget,
496 button_motion,
497 factory);
498 object_unref(obj);
499 preview_unset_tmp_obj (obj);
500 preview_redraw ();
501 obj = NULL;
502 main_clear_dimension();
503 }
504 return TRUE;
505 }
506 } else {
507 if (event->button == 1) {
508 factory = ((ObjectFactory_t*(*)(guint)) data)(event->state);
509 obj = object_factory_create_object(factory, x, y);
510 preview_set_tmp_obj (obj);
511
512 g_signal_connect(widget, "motion-notify-event",
513 G_CALLBACK(button_motion), factory);
514 }
515 }
516 return FALSE;
517 }
518
519 ObjectList_t*
make_object_list(void)520 make_object_list(void)
521 {
522 return g_new0 (ObjectList_t, 1);
523 }
524
525 void
object_list_destruct(ObjectList_t * list)526 object_list_destruct(ObjectList_t *list)
527 {
528 object_list_remove_all(list);
529 g_free(list->list);
530 }
531
532 ObjectList_t*
object_list_append_list(ObjectList_t * des,ObjectList_t * src)533 object_list_append_list(ObjectList_t *des, ObjectList_t *src)
534 {
535 GList *p;
536 if (!src)
537 return des;
538 for (p = src->list; p; p = p->next)
539 object_list_append(des, object_clone((Object_t*) p->data));
540 object_list_set_changed(des, TRUE);
541 return des;
542 }
543
544 ObjectList_t*
object_list_copy(ObjectList_t * des,ObjectList_t * src)545 object_list_copy(ObjectList_t *des, ObjectList_t *src)
546 {
547 if (des)
548 object_list_remove_all(des);
549 else
550 des = make_object_list();
551
552 return object_list_append_list(des, src);
553 }
554
555 void
object_list_append(ObjectList_t * list,Object_t * object)556 object_list_append(ObjectList_t *list, Object_t *object)
557 {
558 object->list = list;
559 list->list = g_list_append(list->list, (gpointer) object);
560 object_list_set_changed(list, TRUE);
561 object_list_callback_call(&list->add_cb, object);
562 }
563
564 void
object_list_prepend(ObjectList_t * list,Object_t * object)565 object_list_prepend(ObjectList_t *list, Object_t *object)
566 {
567 object->list = list;
568 list->list = g_list_prepend(list->list, (gpointer) object);
569 object_list_set_changed(list, TRUE);
570 object_list_callback_call(&list->add_cb, object);
571 }
572
573 void
object_list_insert(ObjectList_t * list,gint position,Object_t * object)574 object_list_insert(ObjectList_t *list, gint position, Object_t *object)
575 {
576 object->list = list;
577 list->list = g_list_insert(list->list, (gpointer) object, position);
578 object_list_set_changed(list, TRUE);
579 object_list_callback_call(&list->add_cb, object);
580 }
581
582 void
object_list_remove(ObjectList_t * list,Object_t * object)583 object_list_remove(ObjectList_t *list, Object_t *object)
584 {
585 list->list = g_list_remove(list->list, (gpointer) object);
586 object_list_set_changed(list, TRUE);
587 object_list_callback_call(&list->remove_cb, object);
588 object_unref(object);
589 }
590
591 void
object_list_remove_link(ObjectList_t * list,GList * link)592 object_list_remove_link(ObjectList_t *list, GList *link)
593 {
594 list->list = g_list_remove_link(list->list, link);
595 object_list_set_changed(list, TRUE);
596 object_list_callback_call(&list->remove_cb, (Object_t*) link->data);
597 }
598
599 void
object_list_update(ObjectList_t * list,Object_t * object)600 object_list_update(ObjectList_t *list, Object_t *object)
601 {
602 object_list_callback_call(&list->update_cb, object);
603 }
604
605 void
object_list_draw(ObjectList_t * list,cairo_t * cr)606 object_list_draw(ObjectList_t *list, cairo_t *cr)
607 {
608 GList *p;
609 for (p = list->list; p; p = p->next)
610 object_draw((Object_t*) p->data, cr);
611 }
612
613 void
object_list_draw_selected(ObjectList_t * list,cairo_t * cr)614 object_list_draw_selected(ObjectList_t *list, cairo_t *cr)
615 {
616 GList *p;
617 for (p = list->list; p; p = p->next) {
618 Object_t *obj = (Object_t*) p->data;
619 if (obj->selected)
620 object_draw(obj, cr);
621 }
622 }
623
624 Object_t*
object_list_find(ObjectList_t * list,gint x,gint y)625 object_list_find(ObjectList_t *list, gint x, gint y)
626 {
627 Object_t *found = NULL;
628 GList *p;
629 for (p = list->list; p; p = p->next) {
630 Object_t *obj = (Object_t*) p->data;
631 if (obj->class->point_is_on(obj, x, y))
632 found = obj;
633 }
634 return found;
635 }
636
637 Object_t*
object_list_near_sash(ObjectList_t * list,gint x,gint y,MoveSashFunc_t * sash_func)638 object_list_near_sash(ObjectList_t *list, gint x, gint y,
639 MoveSashFunc_t *sash_func)
640 {
641 Object_t *found = NULL;
642 GList *p;
643 for (p = list->list; p; p = p->next) {
644 Object_t *obj = (Object_t*) p->data;
645 if (obj->selected) {
646 MoveSashFunc_t func = obj->class->near_sash(obj, x, y);
647 if (func) {
648 found = obj;
649 *sash_func = func;
650 }
651 }
652 }
653 return found;
654 }
655
656 void
object_list_remove_all(ObjectList_t * list)657 object_list_remove_all(ObjectList_t *list)
658 {
659 GList *p;
660 for (p = list->list; p; p = p->next) {
661 Object_t *obj = (Object_t*) p->data;
662 object_list_callback_call(&list->remove_cb, obj);
663 object_unref(obj);
664 }
665 g_list_free(list->list);
666 list->list = NULL;
667 object_list_set_changed(list, TRUE);
668 }
669
670 void
clear_paste_buffer(void)671 clear_paste_buffer(void)
672 {
673 if (_paste_buffer)
674 object_list_remove_all(_paste_buffer);
675 else
676 _paste_buffer = make_object_list();
677 }
678
679 ObjectList_t*
get_paste_buffer(void)680 get_paste_buffer(void)
681 {
682 return _paste_buffer;
683 }
684
685 gint
object_list_cut(ObjectList_t * list)686 object_list_cut(ObjectList_t *list)
687 {
688 GList *p, *q;
689 gint count = 0;
690
691 clear_paste_buffer();
692 for (p = list->list; p; p = q) {
693 Object_t *obj = (Object_t*) p->data;
694 q = p->next;
695 if (obj->selected) {
696 if (obj->locked) {
697 do_object_locked_dialog();
698 } else {
699 object_list_append(_paste_buffer, obj);
700 object_list_remove_link(list, p);
701 count++;
702 }
703 }
704 }
705 object_list_set_changed(list, (count) ? TRUE : FALSE);
706 return count;
707 }
708
709 void
object_list_copy_to_paste_buffer(ObjectList_t * list)710 object_list_copy_to_paste_buffer(ObjectList_t *list)
711 {
712 GList *p;
713
714 clear_paste_buffer();
715 for (p = list->list; p; p = p->next) {
716 Object_t *obj = (Object_t*) p->data;
717 if (obj->selected)
718 object_list_append(_paste_buffer, object_clone(obj));
719 }
720 }
721
722 void
object_list_paste(ObjectList_t * list)723 object_list_paste(ObjectList_t *list)
724 {
725 object_list_append_list(list, _paste_buffer);
726 }
727
728 void
object_list_delete_selected(ObjectList_t * list)729 object_list_delete_selected(ObjectList_t *list)
730 {
731 GList *p, *q;
732 for (p = list->list; p; p = q) {
733 Object_t *obj = (Object_t*) p->data;
734 q = p->next;
735 if (obj->selected) {
736 if (obj->locked) {
737 do_object_locked_dialog();
738 } else {
739 object_list_remove_link(list, p);
740 object_unref(obj);
741 }
742 }
743 }
744 }
745
746 void
object_list_edit_selected(ObjectList_t * list)747 object_list_edit_selected(ObjectList_t *list)
748 {
749 GList *p;
750 for (p = list->list; p; p = p->next) {
751 Object_t *obj = (Object_t*) p->data;
752 if (obj->selected) {
753 object_edit(obj, TRUE);
754 break;
755 }
756 }
757 }
758
759 gint
object_list_select_all(ObjectList_t * list)760 object_list_select_all(ObjectList_t *list)
761 {
762 GList *p;
763 gint count = 0;
764 for (p = list->list; p; p = p->next) {
765 Object_t *obj = (Object_t*) p->data;
766 if (!obj->selected) {
767 object_select(obj);
768 count++;
769 }
770 }
771 return count;
772 }
773
774 void
object_list_select_next(ObjectList_t * list)775 object_list_select_next(ObjectList_t *list)
776 {
777 GList *p;
778 for (p = list->list; p; p = p->next) {
779 Object_t *obj = (Object_t*) p->data;
780 if (obj->selected) {
781 object_unselect(obj);
782 p = (p->next) ? p->next : list->list;
783 object_select((Object_t*) p->data);
784 for (p = p->next; p; p = p->next) {
785 obj = (Object_t*) p->data;
786 if (obj->selected)
787 object_unselect(obj);
788 }
789 break;
790 }
791 }
792 }
793
object_list_select_prev(ObjectList_t * list)794 void object_list_select_prev(ObjectList_t *list)
795 {
796 GList *p;
797 for (p = list->list; p; p = p->next) {
798 Object_t *obj = (Object_t*) p->data;
799 if (obj->selected) {
800 GList *q = (p->prev) ? p->prev : g_list_last(list->list);
801 for (; p; p = p->next) {
802 obj = (Object_t*) p->data;
803 if (obj->selected)
804 object_unselect(obj);
805 }
806 object_select((Object_t*) q->data);
807 break;
808 }
809 }
810 }
811
812 gint
object_list_select_region(ObjectList_t * list,gint x,gint y,gint width,gint height)813 object_list_select_region(ObjectList_t *list, gint x, gint y, gint width,
814 gint height)
815 {
816 GList *p;
817 gint count = 0;
818 for (p = list->list; p; p = p->next) {
819 Object_t *obj = (Object_t*) p->data;
820 gint obj_x, obj_y, obj_width, obj_height;
821
822 object_get_dimensions(obj, &obj_x, &obj_y, &obj_width, &obj_height);
823 if (obj_x >= x && obj_x + obj_width <= x + width &&
824 obj_y >= y && obj_y + obj_height <= y + height) {
825 object_select(obj);
826 count++;
827 }
828 }
829 return count;
830 }
831
832 gint
object_list_deselect_all(ObjectList_t * list,Object_t * exception)833 object_list_deselect_all(ObjectList_t *list, Object_t *exception)
834 {
835 GList *p;
836 gint count = 0;
837 for (p = list->list; p; p = p->next) {
838 Object_t *obj = (Object_t*) p->data;
839 if (obj->selected && obj != exception) {
840 object_unselect(obj);
841 count++;
842 }
843 }
844 return count;
845 }
846
847 gint
object_list_nr_selected(ObjectList_t * list)848 object_list_nr_selected(ObjectList_t *list)
849 {
850 GList *p;
851 gint count = 0;
852 for (p = list->list; p; p = p->next) {
853 Object_t *obj = (Object_t*) p->data;
854 if (obj->selected)
855 count++;
856 }
857 return count;
858 }
859
860 void
object_list_resize(ObjectList_t * list,gint percentage_x,gint percentage_y)861 object_list_resize(ObjectList_t *list, gint percentage_x, gint percentage_y)
862 {
863 GList *p;
864 for (p = list->list; p; p = p->next) {
865 Object_t *obj = (Object_t*) p->data;
866 object_resize(obj, percentage_x, percentage_y);
867 }
868 }
869
870 static void
object_list_swap_prev(ObjectList_t * list,GList * p)871 object_list_swap_prev(ObjectList_t *list, GList *p)
872 {
873 gpointer swap = p->data;
874 p->data = p->prev->data;
875 p->prev->data = swap;
876 object_list_callback_call(&list->move_cb, (Object_t*) p->data);
877 object_list_callback_call(&list->move_cb, (Object_t*) p->prev->data);
878 }
879
880 static void
object_list_swap_next(ObjectList_t * list,GList * p)881 object_list_swap_next(ObjectList_t *list, GList *p)
882 {
883 gpointer swap = p->data;
884 p->data = p->next->data;
885 p->next->data = swap;
886 object_list_callback_call(&list->move_cb, (Object_t*) p->data);
887 object_list_callback_call(&list->move_cb, (Object_t*) p->next->data);
888 }
889
890 void
object_list_move_selected(ObjectList_t * list,gint dx,gint dy)891 object_list_move_selected(ObjectList_t *list, gint dx, gint dy)
892 {
893 GList *p;
894 for (p = list->list; p; p = p->next) {
895 Object_t *obj = (Object_t*) p->data;
896 if (obj->selected)
897 object_move(obj, dx, dy);
898 }
899 }
900
901 void
object_list_move_up(ObjectList_t * list,Object_t * obj)902 object_list_move_up(ObjectList_t *list, Object_t *obj)
903 {
904 GList *p = g_list_find(list->list, (gpointer) obj);
905 object_list_swap_prev(list, p);
906 }
907
908 void
object_list_move_down(ObjectList_t * list,Object_t * obj)909 object_list_move_down(ObjectList_t *list, Object_t *obj)
910 {
911 GList *p = g_list_find(list->list, (gpointer) obj);
912 object_list_swap_next(list, p);
913 }
914
915 void
object_list_move_selected_up(ObjectList_t * list)916 object_list_move_selected_up(ObjectList_t *list)
917 {
918 GList *p;
919
920 for (p = list->list; p; p = p->next) {
921 Object_t *obj = (Object_t*) p->data;
922 if (obj->selected && p->prev)
923 object_list_swap_prev(list, p);
924 }
925 }
926
927 void
object_list_move_selected_down(ObjectList_t * list)928 object_list_move_selected_down(ObjectList_t *list)
929 {
930 GList *p;
931
932 for (p = g_list_last(list->list); p; p = p->prev) {
933 Object_t *obj = (Object_t*) p->data;
934 if (obj->selected && p->next)
935 object_list_swap_next(list, p);
936 }
937 }
938
939 void
object_list_move_to_front(ObjectList_t * list)940 object_list_move_to_front(ObjectList_t *list)
941 {
942 GList *p, *q;
943 guint length = g_list_length(list->list);
944
945 for (p = list->list; length; p = q, length--) {
946 Object_t *obj = (Object_t*) p->data;
947 q = p->next;
948 if (obj->selected) {
949 object_list_remove_link(list, p);
950 object_list_append(list, obj);
951 }
952 }
953 }
954
955 void
object_list_send_to_back(ObjectList_t * list)956 object_list_send_to_back(ObjectList_t *list)
957 {
958 GList *p, *q;
959 guint length = g_list_length(list->list);
960
961 for (p = list->list; length; p = q, length--) {
962 Object_t *obj = (Object_t*) p->data;
963 q = p->next;
964 if (obj->selected) {
965 object_list_remove_link(list, p);
966 object_list_prepend(list, obj);
967 }
968 }
969 }
970
971 void
object_list_move_sash_selected(ObjectList_t * list,gint dx,gint dy)972 object_list_move_sash_selected(ObjectList_t *list, gint dx, gint dy)
973 {
974 GList *p;
975 for (p = list->list; p; p = p->next) {
976 Object_t *obj = (Object_t*) p->data;
977 if (obj->selected)
978 object_move_sash(obj, dx, dy);
979 }
980 }
981
982 static void
write_xml_attrib(const gchar * attrib,const gchar * value,const gchar * default_text,gpointer param,OutputFunc_t output)983 write_xml_attrib(const gchar *attrib, const gchar *value,
984 const gchar *default_text, gpointer param,
985 OutputFunc_t output)
986 {
987 if (*value) {
988 gchar *escaped_value = g_markup_escape_text(value, -1);
989 output(param, " %s=\"%s\"", attrib, escaped_value);
990 g_free(escaped_value);
991 } else if (*default_text) {
992 output(param, " %s", default_text);
993 }
994 }
995
996 void
object_list_write_csim(ObjectList_t * list,gpointer param,OutputFunc_t output)997 object_list_write_csim(ObjectList_t *list, gpointer param, OutputFunc_t output)
998 {
999 GList *p;
1000 for (p = list->list; p; p = p->next) {
1001 Object_t *obj = (Object_t*) p->data;
1002
1003 output(param, "<area shape=");
1004 obj->class->write_csim(obj, param, output);
1005
1006 write_xml_attrib("alt", obj->comment, "", param, output);
1007 write_xml_attrib("target", obj->target, "", param, output);
1008 write_xml_attrib("onmouseover", obj->mouse_over, "", param, output);
1009 write_xml_attrib("onmouseout", obj->mouse_out, "", param, output);
1010 write_xml_attrib("onfocus", obj->focus, "", param, output);
1011 write_xml_attrib("onblur", obj->blur, "", param, output);
1012 write_xml_attrib("href", obj->url, " nohref=\"nohref\"", param, output);
1013 output(param," />\n");
1014 }
1015 }
1016
1017 void
object_list_write_cern(ObjectList_t * list,gpointer param,OutputFunc_t output)1018 object_list_write_cern(ObjectList_t *list, gpointer param, OutputFunc_t output)
1019 {
1020 GList *p;
1021 for (p = list->list; p; p = p->next) {
1022 Object_t *obj = (Object_t*) p->data;
1023 obj->class->write_cern(obj, param, output);
1024 output(param, " %s\n", obj->url);
1025 }
1026 }
1027
1028 void
object_list_write_ncsa(ObjectList_t * list,gpointer param,OutputFunc_t output)1029 object_list_write_ncsa(ObjectList_t *list, gpointer param, OutputFunc_t output)
1030 {
1031 GList *p;
1032 for (p = list->list; p; p = p->next) {
1033 Object_t *obj = (Object_t*) p->data;
1034
1035 if (*obj->comment)
1036 output(param, "# %s\n", obj->comment);
1037 obj->class->write_ncsa(obj, param, output);
1038 output(param, "\n");
1039 }
1040 }
1041