home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / imagemap / imap_object.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-05-22  |  23.2 KB  |  984 lines

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