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_command.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-05-22  |  9.3 KB  |  383 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 <stdio.h>
  25. #include "imap_command.h"
  26.  
  27. #define INFINITE_UNDO_LEVELS -1
  28.  
  29. static void command_destruct(Command_t *command);
  30.  
  31. static CommandList_t _command_list = {NULL, DEFAULT_UNDO_LEVELS};
  32. static CommandList_t *_current_command_list = &_command_list;
  33.  
  34. static void 
  35. command_list_callback_add(CommandListCallback_t *list, 
  36.               CommandListCallbackFunc_t func, gpointer data)
  37. {
  38.    CommandListCB_t *cb = g_new(CommandListCB_t, 1);
  39.    cb->func = func;
  40.    cb->data = data;
  41.    list->list = g_list_append(list->list, cb);
  42. }
  43.  
  44. static void 
  45. command_list_callback_call(CommandListCallback_t *list, Command_t *command)
  46. {
  47.    GList *p;
  48.    for (p = list->list; p; p = p->next) {
  49.       CommandListCB_t *cb = (CommandListCB_t*) p->data;
  50.       cb->func(command, cb->data);
  51.    }
  52. }
  53.  
  54. CommandList_t* 
  55. command_list_new(gint undo_levels)
  56. {
  57.    CommandList_t *list = g_new(CommandList_t, 1);
  58.    list->parent = NULL;
  59.    list->undo_levels = undo_levels;
  60.    list->list = NULL;
  61.    list->undo = NULL;
  62.    list->redo = NULL;
  63.    list->update_cb.list = NULL;
  64.    return list;
  65. }
  66.  
  67. static void
  68. command_list_clear(CommandList_t *list)
  69. {
  70.    GList *p;
  71.    for (p = list->list; p; p = p->next)
  72.       command_destruct((Command_t*) p->data);
  73.    g_list_free(list->list);
  74.    list->list = NULL;
  75.    list->undo = NULL;
  76.    list->redo = NULL;
  77.    command_list_callback_call(&list->update_cb, NULL);
  78. }
  79.  
  80. void 
  81. command_list_destruct(CommandList_t *list)
  82. {
  83.    command_list_clear(list);
  84.    g_free(list);
  85. }
  86.  
  87. void
  88. command_list_remove_all(void)
  89. {
  90.    command_list_clear(&_command_list);
  91. }
  92.  
  93. static void
  94. _command_list_add(CommandList_t *list, Command_t *command)
  95. {
  96.    GList *p, *q;
  97.  
  98.    /* Remove rest */
  99.    for (p = list->redo; p; p = q) {
  100.       Command_t *curr = (Command_t*) p->data;
  101.       q = p->next;
  102.       command_destruct(curr);
  103.       list->list = g_list_remove_link(list->list, p);
  104.    }
  105.  
  106.    if (g_list_length(list->list) == list->undo_levels) {
  107.       GList *first = g_list_first(list->list);
  108.       Command_t *curr = (Command_t*) first->data;
  109.       command_destruct(curr);
  110.       list->list = g_list_remove_link(list->list, first);
  111.    }
  112.    list->list = g_list_append(list->list, (gpointer) command);
  113.    list->undo = g_list_last(list->list);
  114.    list->redo = NULL;
  115.  
  116.    command_list_callback_call(&list->update_cb, command);
  117. }
  118.  
  119. void
  120. command_list_add(Command_t *command)
  121. {
  122.    _command_list_add(_current_command_list, command);
  123. }
  124.  
  125. /* Fix me! */
  126. void
  127. subcommand_list_add(CommandList_t *list, Command_t *command)
  128. {
  129.    _command_list_add(list, command);
  130. }
  131.  
  132. static CommandClass_t parent_command_class = {
  133.    NULL,            /* parent_command_destruct */
  134.    NULL,            /* parent_command_execute */
  135.    NULL,            /* parent_command_undo */
  136.    NULL                /* parent_command_redo */
  137. };
  138.  
  139. static Command_t*
  140. command_list_start(CommandList_t *list, const gchar *name)
  141. {
  142.    Command_t *command = g_new(Command_t, 1);
  143.    command_init(command, name, &parent_command_class);
  144.    command->sub_commands = command_list_new(INFINITE_UNDO_LEVELS);
  145.  
  146.    command_list_add(command);
  147.    command->sub_commands->parent = _current_command_list;
  148.    _current_command_list = command->sub_commands;
  149.  
  150.    return command;
  151. }
  152.  
  153. static void
  154. command_list_end(CommandList_t *list)
  155. {
  156.    _current_command_list = list->parent;
  157. }
  158.  
  159. Command_t*
  160. subcommand_start(const gchar *name)
  161. {
  162.    return command_list_start(_current_command_list, name);
  163. }
  164.  
  165. void
  166. subcommand_end(void)
  167. {
  168.    command_list_end(_current_command_list);
  169. }
  170.  
  171. static void 
  172. _command_list_set_undo_level(CommandList_t *list, gint level)
  173. {
  174.    gint diff = g_list_length(list->list) - level;
  175.    if (diff > 0) {
  176.       GList *p, *q;
  177.       /* first remove data at the front */
  178.       for (p = list->list; diff && p != list->undo; p = q, diff--) {
  179.      Command_t *curr = (Command_t*) p->data;
  180.      q = p->next;
  181.      command_destruct(curr);
  182.      list->list = g_list_remove_link(list->list, p);
  183.       }
  184.  
  185.       /* If still to long start removing redo levels at the end */
  186.       for (p = g_list_last(list->list); diff && p != list->undo; p = q, 
  187.           diff--) {
  188.      Command_t *curr = (Command_t*) p->data;
  189.      q = p->prev;
  190.      command_destruct(curr);
  191.      list->list = g_list_remove_link(list->list, p);
  192.       }
  193.       command_list_callback_call(&list->update_cb, 
  194.                  (Command_t*) list->undo->data);
  195.    }
  196.    list->undo_levels = level;
  197. }
  198.  
  199. void 
  200. command_list_set_undo_level(gint level)
  201. {
  202.    _command_list_set_undo_level(&_command_list, level);
  203. }
  204.  
  205. Command_t*
  206. command_list_get_redo_command(void)
  207. {
  208.    return (_command_list.redo) ? (Command_t*) _command_list.redo->data :
  209.       NULL;
  210. }
  211.  
  212. void 
  213. command_list_add_update_cb(CommandListCallbackFunc_t func, gpointer data)
  214. {
  215.    command_list_callback_add(&_command_list.update_cb, func, data);
  216. }
  217.  
  218. static void
  219. command_destruct(Command_t *command)
  220. {
  221.    if (command->sub_commands)
  222.       command_list_destruct(command->sub_commands);
  223.    if (command->class->destruct)
  224.       command->class->destruct(command);
  225. }
  226.  
  227. static void
  228. command_list_execute(CommandList_t *list)
  229. {
  230.    GList *p;
  231.    for (p = list->list; p; p = p->next) {
  232.       Command_t *command = (Command_t*) p->data;
  233.       if (command->sub_commands)
  234.      command_list_execute(command->sub_commands);
  235.       if (command->class->execute)
  236.      (void) command->class->execute(command);
  237.    }
  238. }
  239.  
  240. void
  241. command_execute(Command_t *command)
  242. {
  243.    if (command->locked) {
  244.       command->locked = FALSE;
  245.    } else {
  246.       if (command->sub_commands)
  247.      command_list_execute(command->sub_commands);
  248.       if (command->class->execute) {
  249.      CmdExecuteValue_t value = command->class->execute(command);
  250.      if (value == CMD_APPEND)
  251.         command_list_add(command);
  252.      else if (value == CMD_DESTRUCT)
  253.         command_destruct(command);
  254.       }
  255.    }
  256. }
  257.  
  258. void
  259. command_redo(Command_t *command)
  260. {
  261.    if (command->sub_commands)
  262.       command_list_redo_all(command->sub_commands);
  263.    if (command->class->redo)
  264.       command->class->redo(command);
  265.    else if (command->class->execute)
  266.       (void) command->class->execute(command);
  267. }
  268.  
  269. void
  270. command_undo(Command_t *command)
  271. {
  272.    if (command->sub_commands)
  273.       command_list_undo_all(command->sub_commands);
  274.    if (command->class->undo)
  275.       command->class->undo(command);
  276. }
  277.  
  278. void 
  279. command_set_name(Command_t *command, const gchar *name)
  280. {
  281.    command->name = name;
  282.    command_list_callback_call(&_command_list.update_cb, command);
  283. }
  284.  
  285. void 
  286. command_list_undo(CommandList_t *list)
  287. {
  288.    Command_t *command = (Command_t*) list->undo->data;
  289.    command_undo(command);
  290.  
  291.    list->redo = list->undo;
  292.    list->undo = list->undo->prev;
  293.    if (list->undo)
  294.       command = (Command_t*) list->undo->data;
  295.    else
  296.       command = NULL;
  297.    command_list_callback_call(&list->update_cb, command);
  298. }
  299.  
  300. void 
  301. command_list_undo_all(CommandList_t *list)
  302. {
  303.    while (list->undo)
  304.       command_list_undo(list);
  305. }
  306.  
  307. void 
  308. last_command_undo(void)
  309. {
  310.    command_list_undo(&_command_list);
  311. }
  312.  
  313. void
  314. command_list_redo(CommandList_t *list)
  315. {
  316.    Command_t *command = (Command_t*) list->redo->data;
  317.    command_redo(command);
  318.  
  319.    list->undo = list->redo;
  320.    list->redo = list->redo->next;
  321.    command_list_callback_call(&list->update_cb, command);
  322. }
  323.  
  324. void
  325. command_list_redo_all(CommandList_t *list)
  326. {
  327.    while (list->redo)
  328.       command_list_redo(list);
  329. }
  330.  
  331. void 
  332. last_command_redo(void)
  333. {
  334.    command_list_redo(&_command_list);
  335. }
  336.  
  337. Command_t*
  338. command_init(Command_t *command, const gchar *name, CommandClass_t *class)
  339. {
  340.    command->sub_commands = NULL;
  341.    command->name = name;
  342.    command->class = class;
  343.    command->locked = FALSE;
  344.    return command;
  345. }
  346.  
  347. void
  348. command_add_subcommand(Command_t *command, Command_t *sub_command)
  349. {
  350.    if (!command->sub_commands)
  351.       command->sub_commands = command_list_new(INFINITE_UNDO_LEVELS);
  352.    subcommand_list_add(command->sub_commands, sub_command);
  353. }
  354.  
  355. static CmdExecuteValue_t basic_command_execute(Command_t *command);
  356.  
  357. static CommandClass_t basic_command_class = {
  358.    NULL,            /* basic_command_destruct */
  359.    basic_command_execute,
  360.    NULL,
  361.    NULL                /* basic_command_redo */
  362. };
  363.  
  364. typedef struct {
  365.    Command_t parent;
  366.    void (*func)(void);
  367. } BasicCommand_t;
  368.  
  369. Command_t*
  370. command_new(void (*func)(void))
  371. {
  372.    BasicCommand_t *command = g_new(BasicCommand_t, 1);
  373.    command->func = func;
  374.    return command_init(&command->parent, "Unknown", &basic_command_class);
  375. }
  376.  
  377. static CmdExecuteValue_t
  378. basic_command_execute(Command_t *command)
  379. {
  380.    ((BasicCommand_t*) command)->func();
  381.    return CMD_DESTRUCT;
  382. }
  383.