summaryrefslogtreecommitdiff
path: root/saedit
diff options
context:
space:
mode:
authorVasily_Makarov <danilka.pro@gmail.com>2011-06-15 18:24:14 +0400
committerVasily_Makarov <danilka.pro@gmail.com>2011-06-15 18:24:14 +0400
commit6c0a4a2bc3809ee49d55fdff7c55c25d3e6ad4a5 (patch)
tree8a43922891e4f5eb7909d8d2b80f64235760e18d /saedit
parent34dbe2ca8daae2595ee6ff37632a15e68fcc7fc2 (diff)
downloadtools-6c0a4a2bc3809ee49d55fdff7c55c25d3e6ad4a5.tar.gz
tools-6c0a4a2bc3809ee49d55fdff7c55c25d3e6ad4a5.tar.bz2
tools-6c0a4a2bc3809ee49d55fdff7c55c25d3e6ad4a5.tar.xz
tools-6c0a4a2bc3809ee49d55fdff7c55c25d3e6ad4a5.zip
saedit: Review code and add some features
Diffstat (limited to 'saedit')
-rw-r--r--saedit/Makefile39
-rw-r--r--saedit/common.h23
-rw-r--r--saedit/config.c83
-rw-r--r--saedit/config.h39
-rw-r--r--saedit/interface.h30
-rw-r--r--saedit/main.c139
-rw-r--r--saedit/main.h148
-rw-r--r--saedit/sae.c45
-rw-r--r--saedit/sae.h59
-rwxr-xr-xsaedit/saeditbin457431 -> 45422 bytes
-rw-r--r--saedit/search.c100
-rw-r--r--saedit/search.h60
-rw-r--r--saedit/xml.c46
-rw-r--r--saedit/xml.h20
14 files changed, 526 insertions, 305 deletions
diff --git a/saedit/Makefile b/saedit/Makefile
index 7c62f6f..19158d3 100644
--- a/saedit/Makefile
+++ b/saedit/Makefile
@@ -1,8 +1,35 @@
-GTK_FLAGS = $(shell pkg-config gtk+-2.0 --cflags --libs) $(shell pkg-config gtksourceview-2.0 --cflags --libs)
-IBUS_FLAGS = $(shell pkg-config ibus-1.0 --cflags --libs)
+ifndef CFLAGS
+ CFLAGS = -O2 -pipe
+endif
+
+ifndef LDFLAGS
+ LDFLAGS =
+endif
+
+LDFLAGS += -export-dynamic
+
+GTK_CFLAGS = `pkg-config --cflags gtk+-2.0 gtksourceview-2.0`
+IBUS_CFLAGS = `pkg-config --cflags ibus-1.0`
+
+GTK_LDFLAGS = `pkg-config --libs gtk+-2.0 gtksourceview-2.0`
+IBUS_LDFLAGS = `pkg-config --libs ibus-1.0`
+
+IBUS_FLAGS = ${IBUS_CFLAGS} ${IBUS_LDFLAGS}
+GTK_FLAGS = ${GTK_CFLAGS} ${GTK_LDFLAGS}
+
OUTPUT = saedit
-all:compile clean
-compile:
- gcc -ggdb3 -O2 ${CFLAGS} ${GTK_FLAGS} ${IBUS_FLAGS} ${LDFLAGS} main.c -o '${OUTPUT}'
+all:clean main.o search.o config.o xml.o sae.o compile
+compile: main.o search.o config.o xml.o
+ gcc ${CFLAGS} ${GTK_FLAGS} ${IBUS_FLAGS} ${LDFLAGS} -o '${OUTPUT}' main.o search.o config.o xml.o sae.o
+main.o: main.c main.h search.h config.h common.h xml.h
+ gcc ${CFLAGS} ${GTK_CFLAGS} ${IBUS_CFLAGS} -c -o main.o main.c
+search.o: search.c search.h common.h
+ gcc ${CFLAGS} ${GTK_CFLAGS} -c -o search.o search.c
+xml.o: xml.c xml.h common.h
+ gcc ${CFLAGS} ${IBUS_FLAGS} -c -o xml.o xml.c
+config.o: config.c config.h common.h
+ gcc ${CFLAGS} ${GTK_CFLAGS} ${IBUS_FLAGS} -c -o config.o config.c
+sae.o: sae.c sae.h common.h
+ gcc ${CFLAGS} ${GTK_CFLAGS} ${IBUS_CFLAGS} -c -o sae.o sae.c
clean:
- rm -rfv *.o~ *.c~ *.h~
+ rm -rfv '${OUTPUT}' *.o *.o~ *.c~ *.h~
diff --git a/saedit/common.h b/saedit/common.h
new file mode 100644
index 0000000..35f1724
--- /dev/null
+++ b/saedit/common.h
@@ -0,0 +1,23 @@
+/*=======================================*\
+| ____ ____ |
+| / \ /\ | |
+| \____ / \ |____ |
+| \ /____\ | |
+| \____/prite / \nimation |____ditor |
+| |
+| Copyleft Vasily_Makarov 2011 |
+| |
+\*=======================================*/
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <glib/gi18n.h>
+
+#define POSTFIX_FOLDER "..."
+#define SEPARATOR_SLASH "/"
+#define GRID_SIZE 32
+#define SPRITE_WIDTH_DEFAULT 64
+#define SPRITE_HEIGHT_DEFAULT 64
+
+#endif
diff --git a/saedit/config.c b/saedit/config.c
new file mode 100644
index 0000000..c514e26
--- /dev/null
+++ b/saedit/config.c
@@ -0,0 +1,83 @@
+/*=======================================*\
+| ____ ____ |
+| / \ /\ | |
+| \____ / \ |____ |
+| \ /____\ | |
+| \____/prite / \nimation |____ditor |
+| |
+| Copyleft Vasily_Makarov 2011 |
+| |
+\*=======================================*/
+
+#include <glib.h>
+#include <ibusxml.h>
+#include "common.h"
+#include "xml.h"
+#include "config.h"
+
+Options *config_options_new() {
+ return g_new0(Options, 1);
+}
+
+void config_options_load_from_file(Options *options,
+ gchar *file,
+ gchar *data_folder) {
+ options->sprites = NULL;
+
+ XMLNode *node = ibus_xml_parse_file(file);
+
+ if (node != NULL) {
+ GList *list = node->sub_nodes;
+ while (TRUE) {
+ list = g_list_find_custom(list, "option", xml_node_compare_with_name_func);
+ if (list == NULL)
+ break;
+ gchar *name_attr = xml_node_get_attr_value(list->data, "name");
+ if (name_attr != NULL) {
+ if (g_strcmp0(name_attr, "sprites") == 0)
+ options->sprites = xml_node_get_attr_value(list->data, "value");
+ }
+ list = list->next;
+ }
+ }
+
+ if (options->sprites == NULL) options->sprites = OPTION_SPRITES_DEFAULT;
+ options->sprites = g_strjoin(SEPARATOR_SLASH, data_folder, options->sprites, NULL);
+}
+
+Keys *config_keys_new() {
+ Keys *keys = g_new0(Keys, 1);
+ keys->clientdata_folder = KEY_CLIENTDATA_FOLDER_DEFAULT;
+ keys->show_grid = KEY_SHOW_GRID_DEFAULT;
+ return keys;
+}
+
+void config_keys_save(Keys *keys) {
+ GKeyFile *key_file = g_key_file_new();
+ g_key_file_set_value(key_file, "General", "ClientdataFolder",
+ g_strjoin(SEPARATOR_SLASH,
+ keys->clientdata_folder,
+ POSTFIX_FOLDER,
+ NULL));
+ g_key_file_set_boolean(key_file, "General", "ShowGrid", keys->show_grid);
+ g_file_set_contents(KEYS_CONFIG_FILE,
+ g_key_file_to_data(key_file, NULL, NULL),
+ -1,
+ NULL);
+ g_key_file_free(key_file);
+}
+
+void config_keys_load(Keys *keys) {
+ GKeyFile *key_file = g_key_file_new();
+
+ g_key_file_load_from_file(key_file,
+ KEYS_CONFIG_FILE,
+ 0,
+ NULL);
+ if (g_key_file_has_key(key_file, "General", "ClientdataFolder", NULL))
+ keys->clientdata_folder = g_key_file_get_value(key_file, "General", "ClientdataFolder", NULL);
+ if (g_key_file_has_key(key_file, "General", "ShowGrid", NULL))
+ keys->show_grid = g_key_file_get_boolean(key_file, "General", "ShowGrid", NULL);
+
+ g_key_file_free(key_file);
+}
diff --git a/saedit/config.h b/saedit/config.h
new file mode 100644
index 0000000..c8904d5
--- /dev/null
+++ b/saedit/config.h
@@ -0,0 +1,39 @@
+/*=======================================*\
+| ____ ____ |
+| / \ /\ | |
+| \____ / \ |____ |
+| \ /____\ | |
+| \____/prite / \nimation |____ditor |
+| |
+| Copyleft Vasily_Makarov 2011 |
+| |
+\*=======================================*/
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#define OPTION_SPRITES_DEFAULT "graphics/sprites/"
+
+#define KEY_SHOW_GRID_DEFAULT TRUE
+#define KEY_CLIENTDATA_FOLDER_DEFAULT ""
+#define KEYS_CONFIG_FILE g_strjoin(SEPARATOR_SLASH, g_get_user_config_dir(), "saedit/config.ini", NULL)
+
+typedef struct {
+ gchar *sprites;
+} Options;
+
+Options *config_options_new();
+void config_options_load_from_file(Options *options,
+ gchar *file,
+ gchar *data_folder);
+
+typedef struct {
+ gchar *clientdata_folder;
+ gboolean show_grid;
+} Keys;
+
+Keys *config_keys_new();
+void config_keys_load(Keys *keys);
+void config_keys_save(Keys *keys);
+
+#endif
diff --git a/saedit/interface.h b/saedit/interface.h
index 6ad1309..e71a8fc 100644
--- a/saedit/interface.h
+++ b/saedit/interface.h
@@ -9,6 +9,10 @@
| |
\*=======================================*/
+void find_menu_item_activate_callback(GtkWidget *menuitem, gpointer user_data) {
+ search_find_dialog_show(win, source_view);
+}
+
void set_up_interface() {
GtkWidget *button = NULL;
GtkWidget *hbox = NULL;
@@ -25,11 +29,13 @@ void set_up_interface() {
GtkSourceLanguageManager *langman = gtk_source_language_manager_get_default();
source_buffer = gtk_source_buffer_new_with_language(gtk_source_language_manager_get_language(langman, "xml"));
+ text = gtk_source_view_new_with_buffer(source_buffer);
+ source_view = text;
+
win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(win), "Sprite Animation Editor");
gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER);
gtk_window_set_icon(GTK_WINDOW(win), icon);
- //gtk_window_set_modal(GTK_WINDOW(win), TRUE);
gtk_widget_realize(win);
g_signal_connect(win, "destroy", G_CALLBACK(save_config_and_quit), NULL);
gtk_widget_set_size_request(win, MIN_WIDTH, MIN_HEIGHT);
@@ -41,6 +47,7 @@ void set_up_interface() {
vbox = gtk_vbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(win), vbox);
+ //Menubar setup
menubar = gtk_menu_bar_new();
gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
@@ -64,12 +71,19 @@ void set_up_interface() {
gtk_menu_set_accel_group(menu, ag);
menuitem = gtk_menu_item_new_with_label(_("Find..."));
- g_signal_connect(menuitem, "activate", show_find_dialog, NULL);
+ g_signal_connect(menuitem, "activate", find_menu_item_activate_callback, NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(menuitem), "<MenuItems>/Search/Find");
gtk_accel_map_change_entry("<MenuItems>/Search/Find", gdk_keyval_from_name("F"), GDK_CONTROL_MASK, TRUE);
+ menuitem = gtk_menu_item_new_with_label(_("Find next"));
+ g_signal_connect(menuitem, "activate", search_find_next, NULL);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+
+ gtk_menu_item_set_accel_path(GTK_MENU_ITEM(menuitem), "<MenuItems>/Search/FindNext");
+ gtk_accel_map_change_entry("<MenuItems>/Search/FindNext", gdk_keyval_from_name("F3"), 0, TRUE);
+
menuitem = gtk_menu_item_new_with_label(_("Search"));
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menuitem);
@@ -102,6 +116,7 @@ void set_up_interface() {
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menuitem);
+ //Help menu
menu = gtk_menu_new();
menuitem = gtk_menu_item_new_with_label(_("About"));
g_signal_connect(menuitem, "activate", show_about_dialog, NULL);
@@ -114,6 +129,7 @@ void set_up_interface() {
hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
+ //Left part setup
vbbox = gtk_vbutton_box_new();
gtk_button_box_set_layout(GTK_BUTTON_BOX(vbbox), GTK_BUTTONBOX_START);
gtk_button_box_set_child_size(GTK_BUTTON_BOX(vbbox), 180, 0);
@@ -126,7 +142,7 @@ void set_up_interface() {
data_folder_chooser_button = gtk_file_chooser_button_new(_("Clientdata folder"), 0);
gtk_box_pack_start(GTK_BOX(vbbox), data_folder_chooser_button, TRUE, TRUE, 0);
gtk_file_chooser_set_action(GTK_FILE_CHOOSER(data_folder_chooser_button), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
- g_signal_connect(data_folder_chooser_button, "selection-changed", G_CALLBACK(data_folder_set_handler), NULL);
+ g_signal_connect(data_folder_chooser_button, "selection-changed", G_CALLBACK(data_folder_set_callback), NULL);
label = gtk_label_new("");
gtk_label_set_markup(GTK_LABEL(label), markup_bold(_("XML source file")));
@@ -159,7 +175,7 @@ void set_up_interface() {
gtk_box_pack_start(GTK_BOX(vbbox), label, TRUE, TRUE, 0);
gen_sae_info->imagesets_combo_box = gtk_combo_box_new_text();
- g_signal_connect(gen_sae_info->imagesets_combo_box, "changed", G_CALLBACK(imagesets_combo_box_changed_handler), NULL);
+ g_signal_connect(gen_sae_info->imagesets_combo_box, "changed", G_CALLBACK(imagesets_combo_box_changed_callback), NULL);
gtk_box_pack_start(GTK_BOX(vbbox), gen_sae_info->imagesets_combo_box, TRUE, TRUE, 0);
label = gtk_label_new("");
@@ -167,7 +183,7 @@ void set_up_interface() {
gtk_box_pack_start(GTK_BOX(vbbox), label, TRUE, TRUE, 0);
gen_sae_info->actions_combo_box = gtk_combo_box_new_text();
- g_signal_connect(gen_sae_info->actions_combo_box, "changed", G_CALLBACK(actions_combo_box_changed_handler), NULL);
+ g_signal_connect(gen_sae_info->actions_combo_box, "changed", G_CALLBACK(actions_combo_box_changed_callback), NULL);
gtk_box_pack_start(GTK_BOX(vbbox), gen_sae_info->actions_combo_box, TRUE, TRUE, 0);
label = gtk_label_new("");
@@ -175,9 +191,10 @@ void set_up_interface() {
gtk_box_pack_start(GTK_BOX(vbbox), label, TRUE, TRUE, 0);
gen_sae_info->animations_combo_box = gtk_combo_box_new_text();
- g_signal_connect(gen_sae_info->animations_combo_box, "changed", G_CALLBACK(animations_combo_box_changed_handler), NULL);
+ g_signal_connect(gen_sae_info->animations_combo_box, "changed", G_CALLBACK(animations_combo_box_changed_callback), NULL);
gtk_box_pack_start(GTK_BOX(vbbox), gen_sae_info->animations_combo_box, TRUE, TRUE, 0);
+ //Right part setup
vpaned = gtk_vpaned_new();
gtk_box_pack_end(GTK_BOX(hbox), vpaned, TRUE, TRUE, 0);
@@ -186,7 +203,6 @@ void set_up_interface() {
gtk_widget_set_size_request(darea, -1, 120);
g_signal_connect(darea, "expose-event", G_CALLBACK(darea_expose_event), gen_sae_info);
- text = gtk_source_view_new_with_buffer(source_buffer);
source_view = text;
gtk_source_view_set_show_line_numbers(GTK_SOURCE_VIEW(text), TRUE);
diff --git a/saedit/main.c b/saedit/main.c
index 25b605f..947b694 100644
--- a/saedit/main.c
+++ b/saedit/main.c
@@ -9,6 +9,19 @@
| |
\*=======================================*/
+#include <stdlib.h>
+#include <gtk/gtk.h>
+#include <gtksourceview/gtksourceview.h>
+#include <gtksourceview/gtksourcelanguagemanager.h>
+#include <gtksourceview/gtksourceiter.h>
+#include <ibusxml.h>
+#include <cairo.h>
+#include <glib/gi18n.h>
+
+#include "common.h"
+#include "xml.h"
+#include "config.h"
+#include "sae.h"
#include "main.h"
#include "search.h"
#include "interface.h"
@@ -18,15 +31,6 @@ void kill_timeout(int tag) {
g_source_remove(tag);
}
-Frame *frame_new(int index, int offsetX, int offsetY, int delay) {
- Frame *res = g_new0(Frame, 1);
- res->index = index;
- res->offsetX = offsetX;
- res->offsetY = offsetY;
- res->delay = delay;
- return res;
-}
-
cairo_surface_t *get_grid_surface(int w, int h) {
cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, (w + 2) * GRID_SIZE, (h + 2) * GRID_SIZE);
cairo_t *cr = cairo_create(surface);
@@ -123,7 +127,7 @@ void free_imagesets(SAEInfo *sae_info) {
}
void free_imageset(SAEInfo *sae_info) {
- sae_info->imageset = imageset_info_new();
+ sae_info->imageset = imageset_new();
sae_info->ground = sae_info_ground_new();
gtk_widget_set_sensitive(imageset_preview_menu_item, FALSE);
}
@@ -152,7 +156,7 @@ void save_to_xml_file(GtkButton *button, gpointer buffer) {
g_file_set_contents(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(xml_file_chooser_button)), gtk_text_buffer_get_text(source_buffer, &start, &end, NULL), -1, NULL);
}
-void data_folder_set_handler(GtkFileChooserButton *widget, gpointer data) {
+void data_folder_set_callback(GtkFileChooserButton *widget, gpointer data) {
config->clientdata_folder = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(data_folder_chooser_button));
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(xml_file_chooser_button), gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget)));
}
@@ -173,33 +177,6 @@ void show_wrong_source_buffer_dialog() {
gtk_widget_show_all(dialog);
}
-gchar* xml_node_get_attr_value(const XMLNode *node, const gchar *attr_name) {
- gchar **attr = node->attributes;
- int i;
- for (i = 0; i < g_strv_length(attr); i += 2)
- if (g_str_equal(attr[i], attr_name))
- return attr[i + 1];
- return NULL;
-}
-
-
-gint xml_node_compare_with_name(gconstpointer a, gconstpointer b) {
- return g_strcmp0((gchar *)b, ((XMLNode *)a)->name);
-}
-
-gint xml_node_compare_with_action_node_by_imageset_name_func(gconstpointer a, gconstpointer b) {
- return g_strcmp0("action", ((XMLNode *)a)->name) ||
- g_strcmp0((gchar *)b, xml_node_get_attr_value((XMLNode *)a, "imageset"));
-}
-
-gint xml_node_compare_with_direction_attr(gconstpointer node, gconstpointer direction) {
- return g_strcmp0((gchar *)direction, xml_node_get_attr_value((XMLNode *)node, "direction"));
-}
-
-gint xml_node_compare_with_name_attr(gconstpointer node, gconstpointer name) {
- return g_strcmp0((gchar *)name, xml_node_get_attr_value((XMLNode *)node, "name"));
-}
-
GdkPixbuf* get_sprite_by_index(size_t index, SAEInfo *sae_info) {
size_t w = sae_info->imageset->spriteset_width/sae_info->imageset->width;
if (sae_info->imageset->spriteset == NULL) return NULL;
@@ -244,7 +221,7 @@ gboolean set_up_imagesets(SAEInfo *sae_info) {
GList *list = sae_info->root->sub_nodes;
XMLNode *node = NULL;
while (TRUE) {
- list = g_list_find_custom(list, "imageset", xml_node_compare_with_name);
+ list = g_list_find_custom(list, "imageset", xml_node_compare_with_name_func);
if (list == NULL)
break;
if (_imagesets_list == NULL) {
@@ -282,7 +259,9 @@ gboolean set_up_animation_by_direction(SAEInfo *sae_info, const gchar *direction
return FALSE;
sae_info->animation = NULL;
- GList *list = g_list_find_custom(sae_info->animations, direction, xml_node_compare_with_direction_attr);
+ GList *list = g_list_find_custom(sae_info->animations,
+ xml_attr_new("direction", direction),
+ xml_node_compare_with_attr_func);
if (list == NULL)
return FALSE;
int count = 0;
@@ -309,13 +288,13 @@ gboolean set_up_animation_by_direction(SAEInfo *sae_info, const gchar *direction
if (delay_attr != NULL)
sscanf(delay_attr, "%d", &delay);
- if (g_strcmp0(node->name, "frame") == 0) {
+ if (g_str_equal(node->name, "frame")) {
gchar *index_attr = xml_node_get_attr_value(node, "index");
if (index_attr != NULL) {
sscanf(index_attr, "%d", &start);
end = start;
}
- } else if (g_strcmp0(node->name, "sequence") == 0) {
+ } else if (g_str_equal(node->name, "sequence")) {
gchar *start_attr = xml_node_get_attr_value(node, "start");
if (start_attr != NULL)
@@ -359,17 +338,19 @@ gboolean show_general_animation(SAEInfo *sae_info) {
XMLNode *node = sae_info->animations->data;
if (node == NULL)
return FALSE;
- animations_combo_box_changed_handler(NULL, NULL);
+ animations_combo_box_changed_callback(NULL, NULL);
}
gboolean set_up_action_by_name(const gchar *name, SAEInfo *sae_info) {
free_animations(sae_info);
- GList *list = g_list_find_custom(sae_info->actions, name, xml_node_compare_with_name_attr);
+ GList *list = g_list_find_custom(sae_info->actions,
+ xml_attr_new("name", name),
+ xml_node_compare_with_attr_func);
if (list == NULL) return FALSE;
list = ((XMLNode *)list->data)->sub_nodes;
gboolean was_direction = FALSE;
while (TRUE) {
- list = g_list_find_custom(list, "animation", xml_node_compare_with_name);
+ list = g_list_find_custom(list, "animation", xml_node_compare_with_name_func);
if (list == NULL)
break;
if (sae_info->animations == NULL) {
@@ -395,13 +376,13 @@ gboolean set_up_action_by_name(const gchar *name, SAEInfo *sae_info) {
return TRUE;
}
-void actions_combo_box_changed_handler(GtkComboBox *widget, gpointer user_data) {
+void actions_combo_box_changed_callback(GtkComboBox *widget, gpointer user_data) {
if (player != NULL)
set_up_action_by_name(gtk_combo_box_get_active_text(widget), player);
set_up_action_by_name(gtk_combo_box_get_active_text(widget), gen_sae_info);
}
-void animations_combo_box_changed_handler(GtkComboBox *widget, gpointer user_data) {
+void animations_combo_box_changed_callback(GtkComboBox *widget, gpointer user_data) {
set_up_animation_by_direction(gen_sae_info, gtk_combo_box_get_active_text(widget));
if (player != NULL) {
set_up_animation_by_direction(player, gtk_combo_box_get_active_text(widget));
@@ -415,7 +396,13 @@ void set_up_imageset_by_name(const gchar *name, SAEInfo *sae_info) {
free_actions(sae_info);
free_animations(sae_info);
- GList *list = g_list_find_custom(sae_info->imagesets, name, xml_node_compare_with_name_attr);
+ GList *list = g_list_find_custom(sae_info->imagesets,
+ xml_attr_new("name", name),
+ xml_node_compare_with_attr_func);
+
+ if (list == NULL)
+ return FALSE;
+
XMLNode *node = list->data;
if (node == NULL)
return;
@@ -454,7 +441,7 @@ void set_up_imageset_by_name(const gchar *name, SAEInfo *sae_info) {
gchar *height = xml_node_get_attr_value(sae_info->imageset->node, "height");
sscanf(height, "%d", &sae_info->imageset->height);
- list = g_list_find_custom(sae_info->root->sub_nodes, "sae", xml_node_compare_with_name);
+ list = g_list_find_custom(sae_info->root->sub_nodes, "sae", xml_node_compare_with_name_func);
if (list != NULL) {
gchar *ground_attr = xml_node_get_attr_value((XMLNode *)list->data, "ground");
if (ground_attr != NULL) {
@@ -481,32 +468,15 @@ void set_up_imageset_by_name(const gchar *name, SAEInfo *sae_info) {
set_sprite_by_index(0, sae_info);
}
-void imagesets_combo_box_changed_handler(GtkComboBox *widget, gpointer user_data) {
+void imagesets_combo_box_changed_callback(GtkComboBox *widget, gpointer user_data) {
if (gtk_combo_box_get_active_text(widget) != NULL)
set_up_imageset_by_name(gtk_combo_box_get_active_text(widget), gen_sae_info);
}
void load_options() {
- paths->sprites = NULL;
gchar *datapath = config->clientdata_folder;
gchar *path = g_strjoin(SEPARATOR_SLASH, datapath, "paths.xml", NULL);
- XMLNode *node = ibus_xml_parse_file(path);
- if (node != NULL) {
- GList *list = node->sub_nodes;
- while (TRUE) {
- list = g_list_find_custom(list, "option", xml_node_compare_with_name);
- if (list == NULL)
- break;
- gchar *name_attr = xml_node_get_attr_value(list->data, "name");
- if (name_attr != NULL) {
- if (g_strcmp0(name_attr, "sprites") == 0)
- paths->sprites = xml_node_get_attr_value(list->data, "value");
- }
- list = list->next;
- }
- }
- if (paths->sprites == NULL) paths->sprites = OPTION_SPRITES_DEFAULT;
- paths->sprites = g_strjoin(SEPARATOR_SLASH, datapath, paths->sprites, NULL);
+ config_options_load_from_file(paths, path, datapath);
}
void parse_xml_text(gchar *text, SAEInfo *sae_info) {
@@ -520,7 +490,7 @@ void parse_xml_text(gchar *text, SAEInfo *sae_info) {
return;
}
- GList *list = g_list_find_custom(_root_node->sub_nodes, "include", xml_node_compare_with_name);
+ GList *list = g_list_find_custom(_root_node->sub_nodes, "include", xml_node_compare_with_name_func);
while (list != NULL) {
XMLNode *node = list->data;
gchar *file_attr = xml_node_get_attr_value(node, "file");
@@ -531,7 +501,7 @@ void parse_xml_text(gchar *text, SAEInfo *sae_info) {
g_list_concat(_root_node->sub_nodes, ibus_xml_parse_buffer(buf)->sub_nodes);
}
if (list->next != NULL)
- list = g_list_find_custom(list->next, "include", xml_node_compare_with_name);
+ list = g_list_find_custom(list->next, "include", xml_node_compare_with_name_func);
else
list = NULL;
}
@@ -612,34 +582,13 @@ void show_imageset_dialog() {
}
void load_config() {
- GKeyFile *key_file = g_key_file_new();
-
- g_key_file_load_from_file(key_file, g_strjoin(SEPARATOR_SLASH, g_get_user_config_dir(), FILE_CONFIG, NULL), G_KEY_FILE_NONE, NULL);
- if (g_key_file_has_key(key_file, "General", "ClientdataFolder", NULL))
- config->clientdata_folder = g_key_file_get_value(key_file, "General", "ClientdataFolder", NULL);
- if (g_key_file_has_key(key_file, "General", "ShowGrid", NULL))
- config->show_grid = g_key_file_get_boolean(key_file, "General", "ShowGrid", NULL);
-
+ config_keys_load(config);
gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(data_folder_chooser_button), config->clientdata_folder);
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(show_grid_menu_item), config->show_grid);
-
- g_key_file_free(key_file);
}
void save_config_and_quit() {
- GKeyFile *key_file = g_key_file_new();
- gchar *fuck = g_key_file_to_data(key_file, NULL, NULL);
- g_key_file_set_value(key_file, "General", "ClientdataFolder",
- g_strjoin(SEPARATOR_SLASH,
- config->clientdata_folder,
- POSTFIX_FOLDER,
- NULL));
- g_key_file_set_boolean(key_file, "General", "ShowGrid", config->show_grid);
- g_file_set_contents(g_strjoin(SEPARATOR_SLASH, g_get_user_config_dir(), FILE_CONFIG, NULL),
- g_key_file_to_data(key_file, NULL, NULL),
- -1,
- NULL);
- g_key_file_free(key_file);
+ config_keys_save(config);
gtk_main_quit();
}
@@ -650,8 +599,8 @@ int main(int argc, char *argv[]) {
icon = gdk_pixbuf_new_from_file(FILE_ICON, NULL);
gen_sae_info = sae_info_new();
- config = keys_new();
- paths = g_new0(Options, 1);
+ config = config_keys_new();
+ paths = config_options_new();
set_up_interface();
load_config();
diff --git a/saedit/main.h b/saedit/main.h
index 3afe623..7cd67b3 100644
--- a/saedit/main.h
+++ b/saedit/main.h
@@ -9,150 +9,17 @@
| |
\*=======================================*/
-#include <stdlib.h>
-#include <gtk/gtk.h>
-#include <gtksourceview/gtksourceview.h>
-#include <gtksourceview/gtksourcelanguagemanager.h>
-#include <gtksourceview/gtksourceiter.h>
-#include <ibusxml.h>
-#include <cairo.h>
-#include <glib/gi18n.h>
-
const int MIN_WIDTH = 600;
const int MIN_HEIGHT = 600;
-const int SPRITE_WIDTH_DEFAULT = 64;
-const int SPRITE_HEIGHT_DEFAULT = 64;
-const int GRID_SIZE = 32;
const gchar *DIR_GROUNDS = "grounds";
const gchar *DIR_PLAYERS = "players/";
const gchar *FILE_ICON = "icon.svg";
-const gchar *FILE_CONFIG = "saedit/config.ini";
-const gchar *POSTFIX_FOLDER = "...";
-const gchar *SEPARATOR_SLASH = "/";
-const gchar *OPTION_SPRITES_DEFAULT = "graphics/sprites/";
-
-const gboolean KEY_SHOW_GRID_DEFAULT = TRUE;
-const gchar *KEY_CLIENTDATA_FOLDER_DEFAULT = "";
const int IMAGESET_PREVIEW_WINDOW_WIDTH = 200;
const int IMAGESET_PREVIEW_WINDOW_HEIGHT = 300;
-typedef struct {
- XMLNode *node;
- int offsetX;
- int offsetY;
- int width;
- int height;
- int spriteset_width;
- int spriteset_height;
- GdkPixbuf *spriteset;
-} ImagesetInfo;
-
-typedef struct {
- int index;
- int offsetX;
- int offsetY;
- int delay;
- GdkPixbuf *pixbuf;
- cairo_surface_t *surface;
-} Frame;
-static Frame *frame_new(int index, int offsetX, int offsetY, int delay);
-
-static ImagesetInfo *imageset_info_new() {
- ImagesetInfo *res = g_new0(ImagesetInfo, 1);
- res->width = SPRITE_WIDTH_DEFAULT;
- res->height = SPRITE_HEIGHT_DEFAULT;
- return res;
-}
-
-typedef struct {
- GList *imagesets;
- GList *actions;
- GList *animations;
- GList *animation;
- ImagesetInfo *imageset;
- Frame *sprite;
- guint anim_tag;
- XMLNode *root;
- GtkWidget *imagesets_combo_box;
- GtkWidget *actions_combo_box;
- GtkWidget *animations_combo_box;
- GdkPixbuf *ground;
- int offsetX;
- int offsetY;
-} SAEInfo;
-
-static GdkPixbuf *sae_info_ground_new() {
- GdkPixbuf *ground = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, GRID_SIZE * 3, GRID_SIZE * 3);
- gdk_pixbuf_fill(ground, 0x00000000);
- return ground;
-}
-
-static SAEInfo *sae_info_new() {
- SAEInfo *res = g_new0(SAEInfo, 1);
- res->ground = sae_info_ground_new();
- res->sprite = frame_new(-1, 0, 0, 0);
- res->imageset = imageset_info_new();
- return res;
-}
-
-
-typedef struct {
- GList *sub_nodes;
- guint *anim_tag;
- SAEInfo *sae_info;
-} AnimationInfo;
-
-static AnimationInfo *animation_info_new() {
- return g_new0(AnimationInfo, 1);
-}
-
-static AnimationInfo *animation_info_new_with_params(GList *sub_nodes_new, guint *anim_tag_new, SAEInfo *sae_info) {
- AnimationInfo *res = animation_info_new();
- res->sub_nodes = sub_nodes_new;
- res->anim_tag = anim_tag_new;
- res->sae_info = sae_info;
- return res;
-}
-
-typedef struct {
- XMLNode *node;
- int start;
- int end;
- guint delay;
- AnimationInfo *anim_info;
- int repeat;
-} SequenceInfo;
-
-static SequenceInfo *sequence_info_new(XMLNode *node, int start, int end, guint delay, AnimationInfo *anim_info, int repeat) {
- SequenceInfo *res = g_new0(SequenceInfo, 1);
- res->start = start;
- res->end = end;
- res->node = node;
- res->delay = delay;
- res->anim_info = anim_info;
- res->repeat = repeat;
- return res;
-}
-
-typedef struct {
- gchar *sprites;
-} Options;
-
-typedef struct {
- gchar *clientdata_folder;
- gboolean show_grid;
-} Keys;
-
-static Keys *keys_new() {
- Keys *res = g_new0(Keys, 1);
- res->clientdata_folder = KEY_CLIENTDATA_FOLDER_DEFAULT;
- res->show_grid = KEY_SHOW_GRID_DEFAULT;
- return res;
-}
-
GtkWidget *win = NULL;
GtkWidget *darea = NULL;
GtkWidget *data_folder_chooser_button = NULL;
@@ -173,7 +40,6 @@ GdkPixbuf *icon = NULL;
Options *paths;
Keys *config;
-static gboolean show_animation_by_info(AnimationInfo *anim_info);
static gchar *markup_bold(gchar *str);
static void format_src_string(gchar *src);
static void open_xml_file(GtkButton *button, gpointer buffer);
@@ -181,24 +47,18 @@ static void free_imagesets(SAEInfo *sae_info);
static void free_actions(SAEInfo *sae_info);
static void free_animations(SAEInfo *sae_info);
static void save_to_xml_file(GtkButton *button, gpointer buffer);
-static void data_folder_set_handler(GtkFileChooserButton *widget, gpointer data);
+static void data_folder_set_callback(GtkFileChooserButton *widget, gpointer data);
static void show_wrong_source_buffer_dialog();
-static gchar* xml_node_get_attr_value(const XMLNode *node, const gchar *attr_name);
-static gint xml_node_compare_with_name(gconstpointer a, gconstpointer b);
-static gint xml_node_compare_with_action_node_by_imageset_name_func(gconstpointer a, gconstpointer b);
-static gint xml_node_compare_with_direction_attr(gconstpointer node, gconstpointer direction);
-static gint xml_node_compare_with_name_attr(gconstpointer node, gconstpointer name);
static GdkPixbuf* get_sprite_by_index(size_t index, SAEInfo *sae_info);
static void set_sprite_by_index(size_t index, SAEInfo *sae_info);
static void set_up_actions_by_imageset_name(gchar *imageset_name, SAEInfo *sae_info);
static gboolean set_up_imagesets(SAEInfo *sae_info);
-static gboolean sequence_source_func(SequenceInfo *seq);
static gboolean show_general_animation(SAEInfo *sae_info);
static gboolean set_up_action_by_name(const gchar *name, SAEInfo *sae_info);
-static void actions_combo_box_changed_handler(GtkComboBox *widget, gpointer user_data);
-static void animations_combo_box_changed_handler(GtkComboBox *widget, gpointer user_data);
+static void actions_combo_box_changed_callback(GtkComboBox *widget, gpointer user_data);
+static void animations_combo_box_changed_callback(GtkComboBox *widget, gpointer user_data);
static void set_up_imageset_by_name(const gchar* name, SAEInfo *sae_info);
-static void imagesets_combo_box_changed_handler(GtkComboBox *widget, gpointer user_data);
+static void imagesets_combo_box_changed_callback(GtkComboBox *widget, gpointer user_data);
static void parse_xml_buffer(GtkWidget *button, GtkSourceBuffer *buffer);
static void set_up_interface();
static void show_about_dialog();
diff --git a/saedit/sae.c b/saedit/sae.c
new file mode 100644
index 0000000..638baca
--- /dev/null
+++ b/saedit/sae.c
@@ -0,0 +1,45 @@
+/*=======================================*\
+| ____ ____ |
+| / \ /\ | |
+| \____ / \ |____ |
+| \ /____\ | |
+| \____/prite / \nimation |____ditor |
+| |
+| Copyleft Vasily_Makarov 2011 |
+| |
+\*=======================================*/
+
+#include <gtk/gtk.h>
+#include <ibusxml.h>
+#include "common.h"
+#include "sae.h"
+
+Frame *frame_new(int index, int offsetX, int offsetY, int delay) {
+ Frame *res = g_new0(Frame, 1);
+ res->index = index;
+ res->offsetX = offsetX;
+ res->offsetY = offsetY;
+ res->delay = delay;
+ return res;
+}
+
+Imageset *imageset_new() {
+ Imageset *res = g_new0(Imageset, 1);
+ res->width = SPRITE_WIDTH_DEFAULT;
+ res->height = SPRITE_HEIGHT_DEFAULT;
+ return res;
+}
+
+SAEInfo *sae_info_new() {
+ SAEInfo *res = g_new0(SAEInfo, 1);
+ res->ground = sae_info_ground_new();
+ res->sprite = frame_new(-1, 0, 0, 0);
+ res->imageset = imageset_new();
+ return res;
+}
+
+GdkPixbuf *sae_info_ground_new() {
+ GdkPixbuf *ground = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, GRID_SIZE * 3, GRID_SIZE * 3);
+ gdk_pixbuf_fill(ground, 0x00000000);
+ return ground;
+}
diff --git a/saedit/sae.h b/saedit/sae.h
new file mode 100644
index 0000000..8f42637
--- /dev/null
+++ b/saedit/sae.h
@@ -0,0 +1,59 @@
+/*=======================================*\
+| ____ ____ |
+| / \ /\ | |
+| \____ / \ |____ |
+| \ /____\ | |
+| \____/prite / \nimation |____ditor |
+| |
+| Copyleft Vasily_Makarov 2011 |
+| |
+\*=======================================*/
+
+#ifndef SAE_H
+#define SAE_H
+
+typedef struct {
+ int index;
+ int offsetX;
+ int offsetY;
+ int delay;
+ GdkPixbuf *pixbuf;
+ cairo_surface_t *surface;
+} Frame;
+
+Frame *frame_new(int index, int offsetX, int offsetY, int delay);
+
+typedef struct {
+ XMLNode *node;
+ int offsetX;
+ int offsetY;
+ int width;
+ int height;
+ int spriteset_width;
+ int spriteset_height;
+ GdkPixbuf *spriteset;
+} Imageset;
+
+Imageset *imageset_new();
+
+typedef struct {
+ GList *imagesets;
+ GList *actions;
+ GList *animations;
+ GList *animation;
+ Imageset *imageset;
+ Frame *sprite;
+ guint anim_tag;
+ XMLNode *root;
+ GtkWidget *imagesets_combo_box;
+ GtkWidget *actions_combo_box;
+ GtkWidget *animations_combo_box;
+ GdkPixbuf *ground;
+ int offsetX;
+ int offsetY;
+} SAEInfo;
+
+SAEInfo *sae_info_new();
+GdkPixbuf *sae_info_ground_new();
+
+#endif
diff --git a/saedit/saedit b/saedit/saedit
index 0a9f3f2..659fc05 100755
--- a/saedit/saedit
+++ b/saedit/saedit
Binary files differ
diff --git a/saedit/search.c b/saedit/search.c
new file mode 100644
index 0000000..b0c5ad1
--- /dev/null
+++ b/saedit/search.c
@@ -0,0 +1,100 @@
+/*=======================================*\
+| ____ ____ |
+| / \ /\ | |
+| \____ / \ |____ |
+| \ /____\ | |
+| \____/prite / \nimation |____ditor |
+| |
+| Copyleft Vasily_Makarov 2011 |
+| |
+\*=======================================*/
+
+#include <gtk/gtk.h>
+#include "common.h"
+#include "search.h"
+
+GtkWidget *search_text_view = NULL;
+GtkWidget *search_find_dialog_entry = NULL;
+gchar *search_last_text = NULL;
+
+gboolean search_find_text(gchar *text) {
+ search_last_text = text;
+
+ GtkTextBuffer *text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(search_text_view));
+ if (!GTK_IS_TEXT_BUFFER(text_buffer))
+ return FALSE;
+
+ gboolean found;
+
+ GtkTextIter m_start, m_end, start;
+ gtk_text_buffer_get_selection_bounds(text_buffer, NULL, &start);
+ found = gtk_source_iter_forward_search(&start, text, 0, &m_start, &m_end, NULL);
+
+ if (!found) {
+ gtk_text_buffer_get_start_iter(text_buffer, &start);
+ found = gtk_source_iter_forward_search(&start, text, 0, &m_start, &m_end, NULL);
+ }
+
+ if (found) {
+ gtk_text_buffer_place_cursor(text_buffer, &m_start);
+ gtk_text_buffer_move_mark_by_name(text_buffer, "selection_bound", &m_end);
+ gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW(search_text_view),
+ gtk_text_buffer_get_insert(text_buffer),
+ 0.25,
+ FALSE,
+ 0.0,
+ 0.0);
+ return TRUE;
+ } else
+ return FALSE;
+}
+
+gboolean search_find_next() {
+ if (search_last_text != NULL)
+ search_find_text(search_last_text);
+}
+
+void search_find_dialog_response_callback(GtkDialog *dialog,
+ gint response_id,
+ gpointer user_data) {
+ if (response_id != GTK_RESPONSE_ACCEPT)
+ return;
+
+ if (!GTK_IS_TEXT_VIEW(search_text_view))
+ return;
+
+ if (GTK_IS_ENTRY(search_find_dialog_entry))
+ search_find_text(g_strdup(gtk_entry_get_text(GTK_ENTRY(search_find_dialog_entry))));
+}
+
+void search_find_dialog_show(GtkWindow *parent,
+ GtkWidget *text_view) {
+ GtkWidget *dialog;
+ GtkWidget *vbox;
+ GtkWidget *entry;
+ GtkWidget *content_area;
+ GtkWidget *label;
+
+ dialog = gtk_dialog_new_with_buttons(_("Find"),
+ parent,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_FIND,
+ GTK_RESPONSE_ACCEPT,
+ NULL);
+ gtk_widget_set_size_request(dialog, 240, 80);
+ gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
+ content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+
+ entry = gtk_entry_new();
+ gtk_container_add(GTK_CONTAINER(content_area), entry);
+
+ g_signal_connect(dialog,
+ "response",
+ G_CALLBACK(search_find_dialog_response_callback),
+ NULL);
+
+ search_text_view = text_view;
+ search_find_dialog_entry = entry;
+
+ gtk_widget_show_all(dialog);
+}
diff --git a/saedit/search.h b/saedit/search.h
index eacdc56..5d2b5ff 100644
--- a/saedit/search.h
+++ b/saedit/search.h
@@ -9,58 +9,12 @@
| |
\*=======================================*/
-GtkWidget *find_entry;
+#ifndef SEARCH_H
+#define SEARCH_H
-static gboolean find_text() {
- gboolean found;
- gchar *text = gtk_entry_get_text(find_entry);
+gboolean search_find_text(gchar *text);
+gboolean search_find_next();
+void search_find_dialog_show(GtkWindow *parent,
+ GtkWidget *text_view);
- GtkTextIter m_start, m_end, start;
- gtk_text_buffer_get_selection_bounds(source_buffer, NULL, &start);
- found = gtk_source_iter_forward_search(&start, text, 0, &m_start, &m_end, NULL);
-
- if (!found) {
- gtk_text_buffer_get_start_iter(source_buffer, &start);
- found = gtk_source_iter_forward_search(&start, text, 0, &m_start, &m_end, NULL);
- }
- if (found) {
- gtk_text_buffer_place_cursor(source_buffer, &m_start);
- gtk_text_buffer_move_mark_by_name(source_buffer, "selection_bound", &m_end);
- gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (source_view),
- gtk_text_buffer_get_insert (source_buffer),
- 0.25,
- FALSE,
- 0.0,
- 0.0);
- return TRUE;
- } else
- return FALSE;
-}
-
-static GtkWidget *show_find_dialog() {
- GtkWidget *dialog;
- GtkWidget *vbox;
- GtkWidget *entry;
- GtkWidget *content_area;
- GtkWidget *label;
-
- dialog = gtk_dialog_new_with_buttons (_("Find"),
- win,
- GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_STOCK_FIND,
- GTK_RESPONSE_NONE,
- NULL);
- gtk_widget_set_size_request(dialog, 240, 80);
- gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
- content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
-
- entry = gtk_entry_new();
- gtk_container_add(GTK_CONTAINER(content_area), entry);
- find_entry = entry;
-
- g_signal_connect(dialog,
- "response",
- G_CALLBACK(find_text),
- NULL);
- gtk_widget_show_all(dialog);
-}
+#endif
diff --git a/saedit/xml.c b/saedit/xml.c
new file mode 100644
index 0000000..6120d5c
--- /dev/null
+++ b/saedit/xml.c
@@ -0,0 +1,46 @@
+/*=======================================*\
+| ____ ____ |
+| / \ /\ | |
+| \____ / \ |____ |
+| \ /____\ | |
+| \____/prite / \nimation |____ditor |
+| |
+| Copyleft Vasily_Makarov 2011 |
+| |
+\*=======================================*/
+
+#include <glib.h>
+#include <ibusxml.h>
+#include "common.h"
+#include "xml.h"
+
+gchar **xml_attr_new(gchar *name, gchar *value) {
+ gchar **attr = g_new0(gchar*, 2);
+ attr[0] = name;
+ attr[1] = value;
+ return attr;
+}
+
+gchar* xml_node_get_attr_value(XMLNode *node, gchar *attr_name) {
+ gchar **attr = node->attributes;
+ int i;
+ for (i = 0; i < g_strv_length(attr); i += 2)
+ if (g_str_equal(attr[i], attr_name))
+ return attr[i + 1];
+ return NULL;
+}
+
+
+gint xml_node_compare_with_name_func(gconstpointer a, gconstpointer b) {
+ return g_strcmp0((gchar *)b, ((XMLNode *)a)->name);
+}
+
+gint xml_node_compare_with_action_node_by_imageset_name_func(gconstpointer a, gconstpointer b) {
+ return g_strcmp0("action", ((XMLNode *)a)->name) ||
+ g_strcmp0((gchar *)b, xml_node_get_attr_value((XMLNode *)a, "imageset"));
+}
+
+gint xml_node_compare_with_attr_func(const XMLNode *node, const gchar **attr) {
+ return g_strcmp0(attr[1],
+ xml_node_get_attr_value(node, attr[0]));
+}
diff --git a/saedit/xml.h b/saedit/xml.h
new file mode 100644
index 0000000..02bd207
--- /dev/null
+++ b/saedit/xml.h
@@ -0,0 +1,20 @@
+/*=======================================*\
+| ____ ____ |
+| / \ /\ | |
+| \____ / \ |____ |
+| \ /____\ | |
+| \____/prite / \nimation |____ditor |
+| |
+| Copyleft Vasily_Makarov 2011 |
+| |
+\*=======================================*/
+#ifndef XML_H
+#define XML_H
+
+gchar **xml_attr_new(gchar *name, gchar *value);
+gchar *xml_node_get_attr_value(XMLNode *node, gchar *attr_name);
+gint xml_node_compare_with_name_func(gconstpointer a, gconstpointer b);
+gint xml_node_compare_with_action_node_by_imageset_name_func(gconstpointer a, gconstpointer b);
+gint xml_node_compare_with_attr_func(const XMLNode *node, const gchar **attr);
+
+#endif