/*  Gnometab -- a guitar tablature editor for GNOME
    Copyright (C) 2001  William L. Guelker

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <math.h>
#include <gnome.h>
#include <libgnomecanvas/gnome-canvas.h>
#include <libgnomeprint/gnome-print.h>
#include <libxml/tree.h>
#include <libxml/parser.h>
#include "tab_canvas.h"
#include "interface.h"
#include "chord_builder.h"
#include "dialogs.h"
#include "tab_doc.h"
#include "tab_objects.h"
#include "chord_canvas.h"
#include "chord_lib.h"
#include "rhythm_builder.h"

static const gchar *canvas_tools[] = {
    "Pointer",
    "Text",
    "Bend",
    "Bar",
    "Slur",
    "Measure",
    "Legato",
    "Strum",
    "Rhythm",
    "Chord",
    "Time Signature",
    "Open Repeat Bar",
    "Close Repeat Bar",
    "Comment",
    "Rest",
    "Library Chord",
    "Text Entry -- Press Arrow keys to position, Enter to accept, Esc to exit"
};

static void 
destroy_tab_object(gpointer tab_object, gpointer user_data)
{
    GnomeCanvasItem *object;
    
    if (GNOME_IS_CANVAS_ITEM(tab_object))    {
        object = GNOME_CANVAS_ITEM(tab_object);
        gtk_object_destroy(GTK_OBJECT(object));
        
    }
}

static void 
clear_clipboard(GtabApp *app)
{
    GList* tmp;
    
    app->clipboard_objs = g_list_first(app->clipboard_objs);
    
    while (app->clipboard_objs != NULL)    {
        tmp = app->clipboard_objs;
        app->clipboard_objs = g_list_next(app->clipboard_objs);
        tmp = g_list_remove(tmp, tmp->data);
    }
    
}

void
destroy_tab_object_and_node_with_cut(gpointer tab_object, gpointer tab_doc)
{
    GnomeCanvasItem *object = NULL;
    xmlNodePtr node, tmp_node;
    
    if (GNOME_IS_CANVAS_ITEM(tab_object))    {
        object = GNOME_CANVAS_ITEM(tab_object);
        ((GtabDoc *)tab_doc)->obj_counter = g_list_remove(((GtabDoc *)tab_doc)->obj_counter, tab_object);
        ((GtabDoc *)tab_doc)->obj_counter = g_list_first(((GtabDoc *)tab_doc)->obj_counter);
        node = (xmlNodePtr ) g_object_get_data(G_OBJECT(object), "node");
        /* xmlUnlinkNode(node);        No way to remove nodes?!?! */
        
        if (node)    {
            if (((GtabDoc *)tab_doc)->parent->clipboard_doc->xmlRootNode != NULL)    {
                /* do clipboard operations */
                tmp_node = xmlCopyNode(node, TRUE);
                tmp_node = xmlAddChild(((GtabDoc *)tab_doc)->parent->clipboard_doc->xmlRootNode,
                                        tmp_node);
            }
            xmlSetProp(node, "active", "false");     /* this sucks    */
        }
        else    {
            fprintf(stderr, "Could not find xml node for object...\n");
        }
        gtk_object_destroy(GTK_OBJECT(object));
    }
}

void
destroy_tab_object_and_node(gpointer tab_object, gpointer tab_doc)
{
    GnomeCanvasItem *object = NULL;
    xmlNodePtr node;
    
    if (GNOME_IS_CANVAS_ITEM(tab_object))    {
        object = GNOME_CANVAS_ITEM(tab_object);
        ((GtabDoc *)tab_doc)->obj_counter = g_list_remove(((GtabDoc *)tab_doc)->obj_counter, tab_object);
        ((GtabDoc *)tab_doc)->obj_counter = g_list_first(((GtabDoc *)tab_doc)->obj_counter);
        node = (xmlNodePtr ) g_object_get_data(G_OBJECT(object), "node");
        /* xmlUnlinkNode(node);        No way to remove nodes?!?! */
        
        if (node)    {
            xmlSetProp(node, "active", "false");     /* this sucks    */
        }
        else    {
            fprintf(stderr, "Could not find xml node for object...\n");
        }
        gtk_object_destroy(GTK_OBJECT(object));
    }
}

void
refresh_canvas(GtabDoc *tab_doc, gboolean newfile)
{
    g_list_foreach(tab_doc->obj_counter, destroy_tab_object, NULL);
    
    g_list_free(tab_doc->obj_counter);
    tab_doc->obj_counter = NULL;
        
    if (GNOME_IS_CANVAS_ITEM(tab_doc->highlights)) {
        gtk_object_destroy(GTK_OBJECT(tab_doc->highlights));
    }
    
    tab_doc->highlights = NULL;
    
    gtk_object_destroy(GTK_OBJECT(tab_doc->staffs));
    gtk_object_destroy(GTK_OBJECT(tab_doc->background));
    
    if (tab_doc->properties != NULL)    {
        gtk_object_destroy(GTK_OBJECT(tab_doc->properties));
        tab_doc->properties = NULL;
    }
        
    /* gnome_appbar_set_default(GNOME_APPBAR
                            (tab_doc->parent->appbar), 
                            "GnomeTab"); */
    
    if (newfile == TRUE)    {
        g_free(tab_doc->filename);
        tab_doc->filename = NULL;
        set_pagenum(tab_doc, 1);
        xmlFreeDoc(tab_doc->current_doc);
        xmlFreeDoc(tab_doc->loaded_doc);
        init_current_doc(tab_doc);
        init_loaded_doc(tab_doc);
        tab_doc->changed = FALSE;
    }
    
    create_staff(tab_doc);
    
}    

void 
create_staff(GtabDoc *tab_doc)
{
    GnomeCanvasItem *staff;
    GnomeCanvasPoints *points;
    gdouble num_staffs = 0.0;
    gdouble num_strings = 0.0;
    gint staff_count = 0;    
    gchar *line_color;
    gdouble lmargin = 50.0;
    gdouble rmargin = 50.0;
    gdouble width = 800.0;
    gdouble height = 1000.0;
    
    line_color = g_strdup("black");
       
    points = gnome_canvas_points_new(4);
    points->coords[0] = 0.0;
    points->coords[1] = 0.0;
    points->coords[2] = width;
    points->coords[3] = 0.0;
    points->coords[4] = width;
    points->coords[5] = height;
    points->coords[6] = 0.0;
    points->coords[7] = height;
    
    tab_doc->background = gnome_canvas_item_new(tab_doc->canvas_group,
                                       gnome_canvas_polygon_get_type(),
                                       "points", points,
                                       "width_pixels", 1,
                                       "fill_color", "white",
                                       "outline_color", "black",
                                       NULL);
                                         
                                        
    g_signal_connect(GTK_OBJECT(tab_doc->canvas_group), 
                        "event", 
                        (GtkSignalFunc) background_event, 
                        tab_doc);
                        
    gnome_canvas_points_unref(points);
    
      /* create the group for staff objects */
    tab_doc->staffs = GNOME_CANVAS_GROUP
                (gnome_canvas_item_new(tab_doc->canvas_group, 
                                    gnome_canvas_group_get_type(), 
                                    NULL));    
    
    for (    num_staffs = 160.0; 
            num_staffs < height; 
            num_staffs = num_staffs + 140.0    )    {
        
        for (    num_strings = 0.0; 
                num_strings < 60.0; 
                num_strings = num_strings + 12.0    )    {
                    
            if (num_strings == 48.0)    {
                /* create the blank bottom rect to catch 6th string mouse 
                   events before drawing the 6th string box itself     */
                g_free(line_color);
                line_color = g_strdup("white");
                points = gnome_canvas_points_new(4);
                points->coords[0] = lmargin;
                points->coords[1] = num_strings + num_staffs + 12.0;
                points->coords[2] = width - rmargin;
                points->coords[3] = num_strings + num_staffs + 12.0;
                points->coords[4] = width - rmargin;
                points->coords[5] = num_strings + num_staffs + 30.0;
                points->coords[6] = lmargin;
                points->coords[7] = num_strings + num_staffs + 30.0;
                
                staff = gnome_canvas_item_new(tab_doc->staffs,
                                          gnome_canvas_polygon_get_type(),
                                            "points", points,
                                            "width_pixels", 1,
                                            "fill_color", "white",
                                          "outline_color", line_color,
                                            NULL);
                  g_signal_connect(GTK_OBJECT(staff), 
                                    "event", (GtkSignalFunc) staff_event, 
                                        tab_doc);
                gnome_canvas_points_unref(points);
                
            }
            g_free(line_color);
            line_color = g_strdup("grey");
            points = gnome_canvas_points_new(4);
            
            points->coords[0] = lmargin;
            points->coords[1] = num_strings + num_staffs;
            points->coords[2] = width - rmargin;
            points->coords[3] = num_strings + num_staffs;
            points->coords[4] = width - rmargin;
            points->coords[5] = num_strings + num_staffs + 12.0;
            points->coords[6] = lmargin;
            points->coords[7] = num_strings + num_staffs + 12.0;
            
            staff = gnome_canvas_item_new(tab_doc->staffs,
                                          gnome_canvas_polygon_get_type(),
                                            "points", points,
                                            "width_pixels", 1,
                                            "fill_color", "white",
                                          "outline_color", line_color,
                                            NULL);
              g_signal_connect(GTK_OBJECT(staff), 
                                "event", (GtkSignalFunc) staff_event, 
                                        tab_doc);
            gnome_canvas_points_unref(points);
        }
        tab_doc->staff_objects[staff_count] = GNOME_CANVAS_GROUP
                                        (gnome_canvas_item_new(tab_doc->staffs, 
                                            gnome_canvas_group_get_type(), 
                                            NULL));
        staff_count++;
    }
    g_free(line_color);
    
}

gint
background_event(GnomeCanvasItem *background, GdkEvent *event, GtabDoc *tab_doc)
{
    static GnomeCanvasItem *select_rect;
    GnomeCanvasPoints *points;
    GdkCursor *fleur;
    static gdouble x, y;
    static guint32 oldtime;
    gdouble new_x, new_y;
    gdouble x1, y1, x2, y2;
    
    if (((GtabApp *)tab_doc->parent)->current_tool != TOOL_POINTER) return TRUE;
        
    switch (event->type)    {
        case GDK_BUTTON_PRESS:
            
                 
            if (staff_select != TRUE && 
                /* try to skip the double clicks */
                (event->button.time - oldtime) > 600)    {
                    
                if (event->button.button == 1)    {
                    staff_select = TRUE;
                    x = event->button.x;
                    y = event->button.y;
                    points = gnome_canvas_points_new(4);
                    points->coords[0] = x;
                    points->coords[1] = y;
                    points->coords[2] = x + 0.5;
                    points->coords[3] = y;
                    points->coords[4] = x + 0.5;
                    points->coords[5] = y + 0.5;
                    points->coords[6] = x;
                    points->coords[7] = y + 0.5;
                    
                    select_rect = gnome_canvas_item_new(tab_doc->canvas_group,
                                                gnome_canvas_polygon_get_type(),
                                                "points", points,
                                                "fill_color", NULL,
                                                "outline_color", "red",
                                                "width_pixels", 2,
                                                NULL);
                    fleur = gdk_cursor_new(GDK_FLEUR);
                    /* fprintf(stderr, "Grabbing.\n"); */
                    gnome_canvas_item_grab(select_rect,
                                                GDK_POINTER_MOTION_MASK |
                                                GDK_BUTTON_RELEASE_MASK,
                                                fleur,
                                                event->button.time);
                    gdk_cursor_destroy(fleur);
                    gnome_canvas_points_unref(points);
                    
                }
            }
            oldtime = event->button.time;
            break;
        
        case GDK_MOTION_NOTIFY:
            new_x = event->button.x;
            new_y = event->button.y;
            
            if (staff_select && (event->motion.state & GDK_BUTTON1_MASK))    {
                if (new_x < x)    {
                    x1 = new_x;
                    x2 = x;
                }
                else    {
                    x1 = x;
                    x2 = new_x;
                }
                if (new_y < y)    {
                    y1 = new_y;
                    y2 = y;
                }
                else    {
                    y1 = y;
                    y2 = new_y;
                }
                
                points = gnome_canvas_points_new(4);
                points->coords[0] = x1;
                points->coords[1] = y1;
                points->coords[2] = x2;
                points->coords[3] = y1;
                points->coords[4] = x2;
                points->coords[5] = y2;
                points->coords[6] = x1;
                points->coords[7] = y2;
                gnome_canvas_item_set(select_rect,
                                    "points", points,
                                    NULL);
                
                gnome_canvas_points_unref(points);
            }
            break;

        case GDK_BUTTON_RELEASE:
            
            if (select_rect)    {
                
                gnome_canvas_item_ungrab(select_rect, event->button.time);
                bulk_select(tab_doc, select_rect);
                gtk_object_destroy(GTK_OBJECT(select_rect));
                
                /* don't pop-up unless something is actually selected */
                if (g_list_length(tab_doc->parent->clipboard_objs) > 0) {
                    gtk_widget_set_sensitive(GTK_WIDGET(
                                g_object_get_data(G_OBJECT(tab_doc->popup->menu), "cut_popup")), TRUE);
                    gtk_widget_set_sensitive(GTK_WIDGET(
                                g_object_get_data(G_OBJECT(tab_doc->popup->menu), "copy_popup")), TRUE);
                    gtk_widget_set_sensitive(GTK_WIDGET(
                                g_object_get_data(G_OBJECT(tab_doc->popup->menu), "paste_popup")), FALSE);
                    gtk_widget_set_sensitive(GTK_WIDGET(
                                g_object_get_data(G_OBJECT(tab_doc->popup->menu), "clear_popup")), TRUE);
                    gtk_menu_popup(GTK_MENU(tab_doc->popup->menu), 
                                    NULL, NULL, NULL, NULL, 1, 0);
                }
            }
            select_rect = NULL;
            staff_select = FALSE;
            break;
            
        default:
            break;
    }
        
    return(TRUE);
}

gint 
staff_event(GnomeCanvasItem *staff, GdkEventButton *event, GtabDoc *tab_doc)
{
    gdouble staff_x1;
    gdouble staff_y1;
    gdouble staff_x2;
    gdouble staff_y2;
    gdouble new_x;
    GtabDialogSlur      *slur_dlg;
    GtabDialogBar       *bar_dlg;
    GtabDialogStrum     *strum_dlg;
    GtabDialogRhythm    *rhthm_dlg;
    GtabDialogTimesig   *timesig_dlg;
    GtabDialogComment   *comment_dlg;
    GtabDialogRest      *rest_dlg;
    GtabChordBuilder    *chord_dlg;
    GtabChordLib        *chord_lib;
        
    if (staff_select == TRUE) return(FALSE);
    
    gnome_appbar_set_status(GNOME_APPBAR(tab_doc->parent->appbar),
                            g_strdup_printf("Current Tool: %s",
                            canvas_tools[tab_doc->parent->current_tool]));
    
    chord_lib = (GtabChordLib *) tab_doc->parent->chord_lib;
    
    gnome_canvas_item_get_bounds(staff, &staff_x1, &staff_y1, 
                                        &staff_x2, &staff_y2);
        
    find_staff(staff_y1);
    
    // moves x to leftmost part of current position        
    new_x = (floor((event->x)/17.0))*17.0;    
    
    switch (event->type)    {
        case GDK_BUTTON_PRESS:
        
            switch (event->button)    {
                case 1:
                        
                    switch (tab_doc->parent->current_tool)    {
                        case TOOL_POINTER:
                            /* don't do anything if pointer is selected */
                            return(FALSE);
                            break;
                        
                        case TOOL_NUM:
                            // make sure we don't get more than one num_entry
                            if (num_entry_bool) return(TRUE);     
                                
                            create_text_entry_widget(tab_doc, new_x, (staff_y1 - 8.0));
                            break;
                                        
                        case TOOL_BEND:
                            create_bend(tab_doc, new_x, staff_y1);
                            break;
                                        
                        case TOOL_SLUR:
                            
                            slur_dlg = create_slur_length_popup(tab_doc);
                            slur_dlg->x = new_x;
                            slur_dlg->y = staff_y1;
                            gtk_widget_show(slur_dlg->dialog);                            
                        
                            break;
                                        
                        case TOOL_BAR:
                                            
                            bar_dlg = create_bar_size_popup(tab_doc);
                            bar_dlg->x = new_x;
                            bar_dlg->y = staff_y1;
                            gtk_widget_show(bar_dlg->dialog);
                            break;
                        
                        case TOOL_MEASURE:
                            create_measure(tab_doc, new_x, staff_y1);
                            break;
                        
                        case TOOL_LEGATO:
                        
                            bar_dlg = create_bar_size_popup(tab_doc);
                            bar_dlg->x = new_x;
                            bar_dlg->y = staff_y1;
                            gtk_widget_show(bar_dlg->dialog);
                            break;
                            
                        case TOOL_STRUM:
                            
                            strum_dlg = create_strum_size_select(tab_doc);
                            strum_dlg->x = new_x;
                            strum_dlg->y = staff_y1;
                            gtk_widget_show(strum_dlg->dialog);
                            break;
                        
                        case TOOL_CHORD:
                            
                            chord_dlg = create_chord_popup(tab_doc);
                            chord_dlg->x = new_x;
                            chord_dlg->y = staff_y1;
                            gtk_widget_show(chord_dlg->dialog);
                            create_grid(chord_dlg);
                            break;
                        
                        case TOOL_LIB_CHORD:
                            
                            if (chord_lib->selected_chord != NULL)    {
                                
                                load_lib_chord(chord_lib, new_x, staff_y1);
                            }
                            tab_doc->parent->current_tool = prior_tool;
                            
                            break;
                        
                        case TOOL_RHYTHM:
                            
                            rhthm_dlg = create_rhythm2_popup(tab_doc);
                            rhthm_dlg->x = new_x;
                            rhthm_dlg->y = staff_y1;
                            gtk_widget_show(rhthm_dlg->dialog);
                            break;
                        
                        case TOOL_TIMESIG:
                            
                            timesig_dlg = create_timesig_popup(tab_doc);
                            timesig_dlg->x = new_x;
                            timesig_dlg->y = staff_y1;
                            gtk_widget_show(timesig_dlg->dialog);
                            break;
                        
                        case TOOL_REPEAT_OPEN:
                            create_repeat_bar(tab_doc, new_x, staff_y1, FALSE);
                            break;
                        
                        case TOOL_REPEAT_CLOSE:
                            create_repeat_bar(tab_doc, new_x, staff_y1, TRUE);
                            break;
                        
                        case TOOL_COMMENT:
                            
                            comment_dlg = create_comment_popup(tab_doc);
                            comment_dlg->x = event->x;
                            comment_dlg->y = event->y;
                            gtk_widget_show(comment_dlg->dialog);
                            break;
                        
                        case TOOL_REST:
                            
                            rest_dlg = create_rest_popup(tab_doc);
                            rest_dlg->x = event->x;
                            rest_dlg->y = event->y;
                            gtk_widget_show(rest_dlg->dialog);
                            break;
                        
                        default:
                            
                            break;
                        
                    }
                    /* make sure to clean up if a chord was
                       chosen and then tool has changed */
                    if (chord_lib->highlights)    {
                        gtk_object_destroy(GTK_OBJECT(chord_lib->highlights));
                        chord_lib->highlights = NULL;
                    }
                    if (chord_lib->selected_chord != NULL)    {
                        xmlFreeNode(chord_lib->selected_chord);
                        chord_lib->selected_chord = NULL;
                    }
                        
                    break;
                
                case 3:
                    tab_doc->popup->x = new_x;
                    tab_doc->popup->y = staff_y1;
                    gtk_widget_set_sensitive(GTK_WIDGET(
                                g_object_get_data(G_OBJECT(tab_doc->popup->menu), "cut_popup")), FALSE);
                    gtk_widget_set_sensitive(GTK_WIDGET(
                                g_object_get_data(G_OBJECT(tab_doc->popup->menu), "copy_popup")), FALSE);
                    gtk_widget_set_sensitive(GTK_WIDGET(
                                g_object_get_data(G_OBJECT(tab_doc->popup->menu), "clear_popup")), FALSE);
                    gtk_menu_popup(GTK_MENU(tab_doc->popup->menu), 
                                        NULL, NULL, NULL, NULL, 1, 0);
                    break;
                
                default:
                    return(TRUE);
                    break;
            }
            return (TRUE);
            break;
        
        default:
            return(TRUE);
            break;
    }
    return(TRUE);
}


gint 
staff_object_event(GnomeCanvasItem *staff_object, GdkEvent *event, GtabDoc *tab_doc)
{
    gdouble item_x, item_y;
    gdouble new_x, new_y;
    static gdouble x, y;
    static gdouble x1_old, y1_old, x2_old, y2_old;
    static gint dragging;
    GdkCursor *fleur;
    static xmlNodePtr node;
    static gdouble y_orig;
    gdouble x1, y1;
    gdouble x_move, y_move;
    gchar *propval;
    
    if (staff_select == TRUE) return(FALSE);
    if (tab_doc->parent->current_tool != TOOL_POINTER) return FALSE;
        
    item_x = event->button.x;
    item_y = event->button.y;

    switch (event->type)    {
        case GDK_BUTTON_PRESS:
            switch (event->button.button)
            {
                case 2:
                    /* do something nifty here */
                
                    break;
                case 3:
                    find_staff(item_y);
                    if (GNOME_IS_CANVAS_ITEM(tab_doc->highlights))    {
                        gtk_object_destroy(GTK_OBJECT(tab_doc->highlights));
                        tab_doc->highlights = NULL;
                    }
                    tab_doc->highlights = GNOME_CANVAS_GROUP
                                (gnome_canvas_item_new
                                        (tab_doc->staff_objects[current_staff],
                                        gnome_canvas_group_get_type(),
                                        NULL));
                    highlight_object(staff_object, tab_doc->highlights);        
                    tab_doc->parent->clipboard_multi = FALSE;
                    /* clipboard_objs = g_list_first(clipboard_objs); */
                    if (g_list_length(tab_doc->parent->clipboard_objs) > 0) 
                                            clear_clipboard(tab_doc->parent);        
                        
                    tab_doc->parent->clipboard_objs = g_list_prepend(tab_doc->parent->clipboard_objs, 
                                                    (gpointer ) staff_object);
                    gtk_widget_set_sensitive(GTK_WIDGET(
                                g_object_get_data(G_OBJECT(tab_doc->popup->menu), "cut_popup")), TRUE);
                    gtk_widget_set_sensitive(GTK_WIDGET(
                                g_object_get_data(G_OBJECT(tab_doc->popup->menu), "copy_popup")), TRUE);
                    gtk_widget_set_sensitive(GTK_WIDGET(
                                g_object_get_data(G_OBJECT(tab_doc->popup->menu), "paste_popup")), FALSE);
                    gtk_widget_set_sensitive(GTK_WIDGET(
                                g_object_get_data(G_OBJECT(tab_doc->popup->menu), "clear_popup")), TRUE);
                    gtk_menu_popup(GTK_MENU(tab_doc->popup->menu),
                                            NULL, NULL, NULL, NULL, 1, 0);
                    break;
                
                case 1:
                    x = item_x;
                    y = item_y;
                    gnome_canvas_item_get_bounds(staff_object, 
                                                &x1_old, &y1_old, 
                                                &x2_old, &y2_old);
                    // node = find_object_node(x1_old, y1_old, x2_old, y2_old);
                    node = (xmlNodePtr ) g_object_get_data(G_OBJECT(staff_object), "node");
                    /* error checking here */
                    if (node)    {
                        fleur = gdk_cursor_new(GDK_FLEUR);
                        find_staff((y1_old + y2_old)/2);
                        switch (current_staff)    {
                            case 1:
                                y_orig = 324.0;
                                break;
                            case 2:
                                y_orig = 464.0;
                                break;
                            case 3:
                                y_orig = 604.0;
                                break;
                            case 4:
                                y_orig = 744.0;
                                break;
                            case 5:
                                y_orig = 884.0;
                                break;
                            default:
                                y_orig = 184.0;
                                break;
                        }
                        
                        gnome_canvas_item_grab(staff_object,
                                                GDK_POINTER_MOTION_MASK |
                                                GDK_BUTTON_RELEASE_MASK,
                                                fleur,
                                                event->button.time);
                        gdk_cursor_destroy(fleur);
                        dragging = TRUE;
                        break;
                    }
                default:
                    
                    break;
                    
            }
            break;
            
        case GDK_MOTION_NOTIFY:
            if (dragging && (event->motion.state & GDK_BUTTON1_MASK))    {
                
                double scale_x1, scale_y1, scale_x2, scale_y2;
                double scale_x_move = 0;
                                
                new_x = item_x;
                new_y = item_y;
                
                /* keep objects on the grid */
                if ((x1_old + (new_x - x)) < 50.0 || 
                    (x2_old + (new_x - x)) > 750.0)    {
                    x_move = 0.0;
                }
                else    {
                    scale_x1 = x;
                    scale_x2 = new_x;
                    scale_y1 = y;
                    scale_y2 = new_y;
                    gnome_canvas_item_w2i(staff_object, &scale_x1, &scale_y1);
                    gnome_canvas_item_w2i(staff_object, &scale_x2, &scale_y2);
                    scale_x_move = (scale_x2 - scale_x1);
                    x_move = (new_x - x);
                }
                /* don't let stuff move too far off of its staff */
                if (fabs((y1_old + y2_old)/2 + (new_y - y) - y_orig) > 50.0 ||
                        (y2_old + (new_y - y) - y_orig) > 50.0 ||
                        (y1_old + (new_y - y) - y_orig) < -50.0)    {
                    y_move = 0.0;
                }
                else    {
                    y_move = (new_y - y);
                }

                // don't let measures or chords or repeats move along y
                // don't let text, rests or timesigs move at all 
                if (g_ascii_strcasecmp(node->name, "tab_text") != 0 && 
                    g_ascii_strcasecmp(node->name, "tab_timesig") != 0 &&
                    // g_ascii_strcasecmp(node->name, "tab_rest") != 0    &&
                    g_ascii_strcasecmp(node->name, "tab_strum") != 0)    {
                        
                    if (g_ascii_strcasecmp(node->name, "tab_chord") == 0 ||
                        g_ascii_strcasecmp(node->name, "tab_measure") == 0 ||
                        g_ascii_strcasecmp(node->name, "tab_repeat") == 0)    {
                            
                        gnome_canvas_item_move(staff_object, scale_x_move, 0.0);
                        x1_old = x1_old + x_move;
                        propval = get_prop(node, "x_create");
                        x1 = atof(propval);
                        g_free(propval);
                        x1 = x1 + x_move;
                        x2_old = x2_old + x_move;
                        
                        xmlSetProp(node, "x_create", float_to_char(x1));
                        
                    }
                    else    {
                        
                        gnome_canvas_item_move(staff_object, x_move, y_move);
                        x1_old = x1_old + x_move;        
                        y1_old = y1_old + y_move;        
                        x2_old = x2_old + x_move;
                        y2_old = y2_old + y_move;
                        propval = get_prop(node, "x_create");
                        x1 = atof(propval);
                        g_free(propval);
                        propval = get_prop(node, "y_create");
                        y1 = atof(propval);
                        g_free(propval);
                        x1 = x1 + x_move;
                        y1 = y1 + y_move;
                        xmlSetProp(node, "x_create", float_to_char(x1));
                        xmlSetProp(node, "y_create", float_to_char(y1));
                    }
                    
                    xmlSetProp(node, "x1", float_to_char(x1_old));
                    xmlSetProp(node, "y1", float_to_char(y1_old));
                    xmlSetProp(node, "x2", float_to_char(x2_old));
                    xmlSetProp(node, "y2", float_to_char(y2_old));
                    
                    tab_doc->changed = TRUE;
                    set_title(tab_doc);
                    x = new_x;
                    y = new_y;
                }
            }
            break;
            
        case GDK_BUTTON_RELEASE:
            gnome_canvas_item_ungrab(staff_object, event->button.time);
            dragging = FALSE;
            break;
        
        default:
            break;
    }        
    
    return(TRUE);
}

        /***** XML UTILITY FUNCTIONS *****/
        
void 
load_tab_file(GtabDoc *tab_doc)
{
    xmlNodePtr tmp_node;
    
    g_return_if_fail(tab_doc->filename != NULL);
    
    xmlFreeDoc(tab_doc->current_doc);
    
    init_current_doc(tab_doc);
    
    xmlFreeDoc(tab_doc->loaded_doc);
    
    tab_doc->loaded_doc = xmlParseFile(tab_doc->filename);
    if (!tab_doc->loaded_doc->xmlRootNode || !tab_doc->loaded_doc->xmlRootNode->name)    {
        gtab_warn(tab_doc->parent, "Error parsing tablature xml file!");
        return;
    }
    for (tmp_node = tab_doc->loaded_doc->xmlRootNode->children; 
            tmp_node != NULL; tmp_node = tmp_node->next)    {
        
        if (xmlIsBlankNode(tmp_node) == 1) continue;
            
        if (g_ascii_strcasecmp(tmp_node->name, "PROPS") == 0)    {
            tab_doc->doc_props = tmp_node;
            
        }
    }
    
    tab_doc->changed = FALSE;
    
}

gint 
save_tab_file(GtabDoc *tab_doc)
{
    gint i;
    
    sync_loaded_doc(tab_doc);
    
    i = xmlSaveFile(tab_doc->filename, tab_doc->loaded_doc);
    if (i != -1)    {
        gnome_app_flash(GNOME_APP(tab_doc->parent->gnometab), 
                                "File Saved.");
        tab_doc->changed = FALSE;
        set_title(tab_doc);
        return(TRUE);
    }
    else    {
        gtab_warn(tab_doc->parent, "Error saving file!");
        return(FALSE);
    }
    
}

void 
sync_loaded_doc(GtabDoc *tab_doc)
{
    gchar *tmp;
    xmlNodePtr page_node;
    xmlNodePtr tmp_node;
    xmlNodePtr tmp_node2;
    xmlNodePtr tmp_node3;
    
    page_node = tab_doc->loaded_doc->xmlRootNode->children;
    
    while (page_node != NULL) {
        if (xmlIsBlankNode(page_node) == 1) {
            page_node = page_node->next;
            continue;
        }
            
        if (g_ascii_strcasecmp(page_node->name, "PROPS") != 0)    {
            tmp = get_prop(page_node, "page");
            if (g_ascii_strcasecmp(tmp, tab_doc->current_page) == 0)    {
                tmp_node3 = xmlCopyNode(tab_doc->current_doc->xmlRootNode, TRUE);
                tmp_node = page_node->next;
                tmp_node2 = xmlReplaceNode(page_node, tmp_node3);
                xmlFreeNode(tmp_node2);
                page_node = tmp_node;
            }
            else    {
                page_node = page_node->next;
            }
            g_free(tmp);
        }
        else    {
            page_node = page_node->next;
        }
            
    }
    
}

void 
file_pre_load(GtabDoc *tab_doc)
{
    GtkProgressBar* progress;
   
    progress = gnome_appbar_get_progress(GNOME_APPBAR
                        (tab_doc->parent->appbar));
    gnome_appbar_set_status(GNOME_APPBAR(tab_doc->parent->appbar), "Loading...");
    
    refresh_canvas(tab_doc, FALSE);
    
    load_tab_file(tab_doc);
    set_pagenum(tab_doc, 1);
    render_current_page(tab_doc, progress);
    
    gnome_appbar_set_status(GNOME_APPBAR(tab_doc->parent->appbar),
                                    g_strdup_printf("Current Tool: %s",
                                    canvas_tools[tab_doc->parent->current_tool]));
    
    tab_doc->changed = FALSE;
    
    set_title(tab_doc);
    
    add_to_history(tab_doc->parent, tab_doc->filename);
    
}

void
set_title(GtabDoc *tab_doc)
{
    gchar* new_title;
    
    if (tab_doc->block_title_updates) return;
        
    if (tab_doc->filename == NULL) {
        if (tab_doc->changed == FALSE) {
            new_title = g_strdup("Gnometab - Untitled");
        }
        else {
            new_title = g_strdup("Gnometab - Untitled (modified)");
        }
    }
    else {
        if (tab_doc->changed == FALSE) {
            new_title = g_strdup_printf("Gnometab - %s", tab_doc->filename);
        }
        else {
            new_title = g_strdup_printf("Gnometab - %s (modified)", tab_doc->filename);
        }
    }
    
    gtk_window_set_title(GTK_WINDOW(tab_doc->parent->gnometab), new_title);
    g_free(new_title);
}


void 
render_current_page(GtabDoc *tab_doc, GtkProgressBar *progress)
{
    xmlNodePtr page_node = NULL;
    xmlNodePtr staff_tmp_node = NULL;
    gchar *tmp;
    gint counter = 0;
    
    current_staff = 0;
    tab_doc->block_title_updates = TRUE;
    
    while (gtk_events_pending())
            gtk_main_iteration();
    
    gtk_progress_bar_set_fraction(progress, 0.0);
    
    gtk_progress_bar_set_pulse_step(progress, 0.4);
    
    for (page_node = tab_doc->loaded_doc->xmlRootNode->children; 
            page_node != NULL; page_node = page_node->next)    {
                
            if (xmlIsBlankNode(page_node) == 1) continue;
                
            if (g_ascii_strcasecmp(page_node->name, "PROPS") != 0)    {
                tmp = get_prop(page_node, "page");        
                if (g_ascii_strcasecmp(tmp, tab_doc->current_page) == 0)    {
                    for(staff_tmp_node = page_node->children; 
                        staff_tmp_node != NULL; 
                        staff_tmp_node = staff_tmp_node->next)    {
                        
                        if (xmlIsBlankNode(staff_tmp_node) == 1) continue;    
                        render_objects(tab_doc, staff_tmp_node);
                        current_staff++;
                        gtk_progress_bar_pulse(progress);
                        
                        // this breaks things....
                        // so no progress bar.  :-(
                        
                        /*while (gtk_events_pending())
                            gtk_main_iteration(); */
                    }
                }
                g_free(tmp);
            }
            else    {
                create_doc_props(tab_doc);
            }
            counter++;
    
        
    }
    
    gtk_progress_bar_pulse(progress);
    gtk_progress_bar_set_fraction(progress, 0.0);
    tab_doc->block_title_updates = FALSE;
    
}

gint
count_page_objects(xmlNodePtr page_node)
{
    xmlNodePtr tmp_node, staff_node;
    gint total = 0;
    gchar *tmp;
    
    for(staff_node = page_node->children; 
        staff_node != NULL; 
        staff_node = staff_node->next)    {
                        
        if (xmlIsBlankNode(staff_node) == 1) continue;    
        for (tmp_node = staff_node->children; 
             tmp_node != NULL;
             tmp_node = tmp_node->next) {
            
            if (xmlIsBlankNode(tmp_node) == 1) continue;
            tmp = get_prop(tmp_node, "active");
            
            if (!tmp) total++;
            
            g_free(tmp);
        }
             
        
    }
    return total;
    
}

void 
render_objects(GtabDoc *tab_doc, xmlNodePtr node)
{
    xmlNodePtr object_node = NULL;
    xmlNodePtr obj_sub_node = NULL;
    xmlDocPtr new_chord = NULL;
    gboolean repeat_bar_close;
    gdouble x;
    gdouble y;
    gchar *tmp, *tmp2, *tmp3, *tmp4, *char_x, *char_y;
    gchar *active, *value, *dotted;
    Tab_Rhythm rhythm;
    
    for (object_node = node->children; 
        object_node != NULL; object_node = object_node->next)    {
        
            if (xmlIsBlankNode(object_node) == 1) continue;
                
            tmp2 = get_prop(object_node, "active");
            if (!tmp2)    {
                
                char_x = get_prop(object_node, "x_create");
                char_y = get_prop(object_node, "y_create");
                x = atof(char_x);
                y = atof(char_y);
                g_free(char_x);
                g_free(char_y);
                if (g_ascii_strcasecmp(object_node->name, "tab_text") == 0)    {
                    tmp = get_prop(object_node, "text");
                    create_text(tab_doc, x, y, tmp);
                    g_free(tmp);
                }
                if (g_ascii_strcasecmp(object_node->name, "tab_bar") == 0)    {
                    tmp = get_prop(object_node, "bar_size");
                    create_bar(tab_doc, x, y, atoi(tmp));
                    g_free(tmp);
                }
                if (g_ascii_strcasecmp(object_node->name, "tab_slur") == 0)    {
                    /* don't want to break some existing xml files */
                    tmp = get_prop(object_node, "type");
                    tmp4 = get_prop(object_node, "positions");
                    if (tmp == NULL)    {
                        create_slur(tab_doc, x, y, 0, atoi(tmp4));
                    }
                    else    {
                        create_slur(tab_doc, x, y, atoi(tmp), atoi(tmp4));
                    }
                    g_free(tmp);
                    g_free(tmp4);
                            
                }
                if (g_ascii_strcasecmp(object_node->name, "tab_bend") == 0)    {
                    create_bend(tab_doc, x, y);
                }
                if (g_ascii_strcasecmp(object_node->name, "tab_measure") == 0)    {
                    create_measure(tab_doc, x, y);
                }
                if (g_ascii_strcasecmp(object_node->name, "tab_legato") == 0)    {
                    tmp = get_prop(object_node, "legato_size");
                    create_legato(tab_doc, x, y, atoi(tmp));
                    g_free(tmp);
                }
                if (g_ascii_strcasecmp(object_node->name, "tab_strum") == 0)    {    
                    tmp = get_prop(object_node, "upstroke");
                    tmp4 = get_prop(object_node, "size");
                    create_strum(tab_doc, x, y,
                            atoi(tmp),
                            atoi(tmp4));
                    g_free(tmp4);
                    g_free(tmp);
                }
                if (g_ascii_strcasecmp(object_node->name, "tab_chord") == 0)    {
                    new_chord = xmlNewDoc("1.0");
                    new_chord->xmlRootNode = xmlCopyNode(object_node, TRUE);
                    translate_chord(tab_doc, x, y, new_chord);
                }
                if (g_ascii_strcasecmp(object_node->name, "tab_timesig") == 0)    {
                    tmp = get_prop(object_node, "beats");
                    tmp4 = get_prop(object_node, "beatval");
                    create_timesig(tab_doc, x, y, atoi(tmp), atoi(tmp4));
                    g_free(tmp);
                    g_free(tmp4);
                }
                if (g_ascii_strcasecmp(object_node->name, "tab_repeat") == 0)    {
                    tmp = get_prop(object_node, "close");
                    repeat_bar_close = atoi(tmp);
                    g_free(tmp);
                    create_repeat_bar(tab_doc, x, y, repeat_bar_close);
                }
                if (g_ascii_strcasecmp(object_node->name, "tab_comment") == 0)    {
                    tmp = get_prop(object_node, "text");
                    create_comment(tab_doc, x, y, tmp);
                    g_free(tmp);
                }
                if (g_ascii_strcasecmp(object_node->name, "tab_rest") == 0)    {
                    tmp = get_prop(object_node, "value");
                    tmp4 = get_prop(object_node, "dotted");
                    create_rest(tab_doc, x, y, atoi(tmp), atoi(tmp4));
                    g_free(tmp);
                    g_free(tmp4);
                }
                    
            }
            else    {
                g_free(tmp2);
            }
        
        
    }
    /* Now cycle through again and render the rhythm */
    for (object_node = node->children; 
            object_node != NULL; 
            object_node = object_node->next)    {
        
        if (xmlIsBlankNode(object_node) == 1) continue;
            
        tmp3 = get_prop(object_node, "active");
        
        if (!tmp3)    {
            char_x = get_prop(object_node, "x_create");
            char_y = get_prop(object_node, "y_create");
            x = atof(char_x);
            y = atof(char_y);
            g_free(char_x);
            g_free(char_y);
            if (g_ascii_strcasecmp(object_node->name, "tab_rhythm") == 0)    {
                gint rhythm_obj_cntr = 0;
                
                // rhythm.start_x = x;
                // rhythm.start_y = y;
                for (obj_sub_node = object_node->children; 
                     obj_sub_node != NULL;
                     obj_sub_node = obj_sub_node->next)    {
                         
                             if (xmlIsBlankNode(obj_sub_node) == 1) continue;
                                 
                             rhythm_obj_cntr++;
                             
                             switch (rhythm_obj_cntr)    {
                                 case 1:
                                     
                    
                                    active = get_prop(obj_sub_node, "active");
                                    value = get_prop(obj_sub_node, "value");
                                    dotted = get_prop(obj_sub_node, "dotted");
                                    rhythm.pos1.active = atoi(active);
                                    rhythm.pos1.value = atoi(value);
                                    rhythm.pos1.dotted = atoi(dotted);
                                    g_free(active);
                                    g_free(value);
                                    g_free(dotted);
                                    break;
                                 
                                 case 2:
                                     
                        
                                    active = get_prop(obj_sub_node, "active");
                                    value = get_prop(obj_sub_node, "value");
                                    dotted = get_prop(obj_sub_node, "dotted");
                                    rhythm.pos2.active = atoi(active);
                                    rhythm.pos2.value = atoi(value);
                                    rhythm.pos2.dotted = atoi(dotted);
                                    g_free(active);
                                    g_free(value);
                                    g_free(dotted);
                                    break;
                                 case 3:
                                     
                
                                    active = get_prop(obj_sub_node, "active");
                                    value = get_prop(obj_sub_node, "value");
                                    dotted = get_prop(obj_sub_node, "dotted");
                                    rhythm.pos3.active = atoi(active);
                                    rhythm.pos3.value = atoi(value);
                                    rhythm.pos3.dotted = atoi(dotted);
                                    g_free(active);
                                    g_free(value);
                                    g_free(dotted);
                                    break;
                                 case 4:
                                     
                
                                    active = get_prop(obj_sub_node, "active");
                                    value = get_prop(obj_sub_node, "value");
                                    dotted = get_prop(obj_sub_node, "dotted");
                                    rhythm.pos4.active = atoi(active);
                                    rhythm.pos4.value = atoi(value);
                                    rhythm.pos4.dotted = atoi(dotted);
                                    g_free(active);
                                    g_free(value);
                                    g_free(dotted);
                                    break;
                                 default:
                                    break;
                             }
                        }
                     
                
                    create_tab_rhythm(tab_doc, rhythm, x, y);
                }
        }
        g_free(tmp3);
                
    }
}
    
void 
find_staff(double y)
{
    
    current_staff = 0;          /* default */
        
    if (y <= 394.0 && y > 254.0) current_staff = 1;
        
    if (y <= 534.0 && y > 394.0) current_staff = 2;
        
    if (y <= 674.0 && y > 534.0) current_staff = 3;
    
    if (y <= 814.0 && y > 674.0) current_staff = 4;
        
    if (y <= 954.0  && y > 814.0) current_staff = 5;
}        


void 
init_current_doc(GtabDoc *tab_doc)
{
    
    tab_doc->current_doc = xmlNewDoc("1.0");
    tab_doc->current_doc->xmlRootNode = xmlNewDocNode(tab_doc->current_doc, NULL, "staff_objects", NULL);
    xmlSetProp(tab_doc->current_doc->xmlRootNode, "page", tab_doc->current_page);
        
    tab_doc->staff_nodes[0] = xmlNewChild(tab_doc->current_doc->xmlRootNode, NULL, "STAFF1", NULL);
    tab_doc->staff_nodes[1] = xmlNewChild(tab_doc->current_doc->xmlRootNode, NULL, "STAFF2", NULL);
    tab_doc->staff_nodes[2] = xmlNewChild(tab_doc->current_doc->xmlRootNode, NULL, "STAFF3", NULL);
    tab_doc->staff_nodes[3] = xmlNewChild(tab_doc->current_doc->xmlRootNode, NULL, "STAFF4", NULL);
    tab_doc->staff_nodes[4] = xmlNewChild(tab_doc->current_doc->xmlRootNode, NULL, "STAFF5", NULL);
    tab_doc->staff_nodes[5] = xmlNewChild(tab_doc->current_doc->xmlRootNode, NULL, "STAFF6", NULL);
    
}

void 
init_loaded_doc(GtabDoc *tab_doc)
{
    xmlNodePtr page_ptr;
    xmlNodePtr tmp_node;
    
    tab_doc->loaded_doc = xmlNewDoc("1.0");
    tab_doc->loaded_doc->xmlRootNode = xmlNewDocNode(tab_doc->loaded_doc, NULL, "tab_doc", NULL);
    page_ptr = xmlCopyNode(tab_doc->current_doc->xmlRootNode, TRUE);
    
    tmp_node = xmlAddChild(tab_doc->loaded_doc->xmlRootNode, page_ptr);
    tab_doc->doc_props = xmlNewChild(tab_doc->loaded_doc->xmlRootNode, NULL, "PROPS", NULL);
}

void
load_chord_lib(GtabApp *app, gchar *filename, gboolean visible)
{
    gboolean     result;
    
    app->chord_lib = create_chord_lib(app);
    
    result = load_chord_lib_file(app->chord_lib, filename);
    
    if (!result) {
        gtk_widget_set_sensitive(GTK_WIDGET(app->btn_lib_chord), FALSE);
        return;
    }
    if (result && visible) {
        render_chord_lib_in_pane(app);
    }
    
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->btn_lib_chord), visible);
}

void
set_pagenum(GtabDoc *tab_doc, gint pagenum)
{
    g_snprintf(tab_doc->current_page, 2, "%i", pagenum);
}
    
gchar* 
int_to_char(gint x)
{
    g_snprintf(return_val, 11, "%i", x);
    return(return_val);
}

gchar* 
float_to_char(double x)
{
    g_snprintf(return_val, 11, "%f", x);
    return(return_val);
}

void 
switch_page(GtabDoc *tab_doc, GtkProgressBar *progress, gboolean up)
{
    xmlNodePtr page_node = NULL;
    xmlNodePtr tmp_node = NULL;
    xmlNodePtr tmp_node2 = NULL;
    xmlNodePtr tmp_node3 = NULL;
    gboolean page_exists = FALSE;
    gboolean old_page_changed;
    gchar *tmp;
    gint counter = 0;
    
    
    old_page_changed = tab_doc->changed;
    
    /* load the current, maybe modified page into loaded doc 
        before clearing current_doc */
    page_node = tab_doc->loaded_doc->xmlRootNode->children;
    
    while (page_node != NULL) {
        
        if (xmlIsBlankNode(page_node) == 1) {
            page_node = page_node->next;
            continue;
        }
            
        if (g_ascii_strcasecmp(page_node->name, "PROPS") != 0)    {
            
            tmp = get_prop(page_node, "page");
            if (g_ascii_strcasecmp(tmp, tab_doc->current_page) == 0)    {
                tmp_node3 = xmlCopyNode(tab_doc->current_doc->xmlRootNode, TRUE);
                tmp_node = page_node->next;
                tmp_node2 = xmlReplaceNode(page_node, tmp_node3);
                xmlFreeNode(tmp_node2);
                page_node = tmp_node;
                
                
            }
            else    {
                page_node = page_node->next;
            }
            g_free(tmp);
        }
        else    {
            page_node = page_node->next;
        }
        counter++;
        
    }
    
    //fprintf(stderr, "nodes in loaded_doc: %i\n", counter);
    counter = 0;
    
    if (up == TRUE)    {
        set_pagenum(tab_doc, atoi(tab_doc->current_page) + 1);
    }
    else    {
        if (atoi(tab_doc->current_page) >= 2)    {
            set_pagenum(tab_doc, atoi(tab_doc->current_page) - 1);
        }
    }
    
    /* check if this page exists already */
    for (page_node = tab_doc->loaded_doc->xmlRootNode->children; 
            page_node != NULL; page_node = page_node->next)    {
        
        if (xmlIsBlankNode(page_node) == 1) continue;
            
        if (g_ascii_strcasecmp(page_node->name, "PROPS") != 0)    {
            tmp = get_prop(page_node, "page");
            if (g_ascii_strcasecmp(tmp, tab_doc->current_page) == 0)    {
                page_exists = TRUE;
            }
            g_free(tmp);
        }
        counter++;
    }
    
    xmlFreeDoc(tab_doc->current_doc);
    init_current_doc(tab_doc);
    if (page_exists == FALSE)    {
        // page_ptr = xmlCopyNode(current_doc->xmlRootNode, TRUE);
        tmp_node = xmlAddChild(tab_doc->loaded_doc->xmlRootNode, 
                                xmlCopyNode(tab_doc->current_doc->xmlRootNode, TRUE));    
        
    }
    
    refresh_canvas(tab_doc, FALSE);
    
    gnome_appbar_set_status(GNOME_APPBAR(tab_doc->parent->appbar), 
                                        "Loading page...");
    
    render_current_page(tab_doc, progress);
    
    gnome_appbar_set_status(GNOME_APPBAR(tab_doc->parent->appbar),
                                    g_strdup_printf("Current Tool: %s",
                                    canvas_tools[tab_doc->parent->current_tool]));
    
    if (!old_page_changed) tab_doc->changed = FALSE;
    
    set_title(tab_doc); 
}

void
highlight_object(GnomeCanvasItem *object, GnomeCanvasGroup *group)
{
    gdouble x1, y1, x2, y2;
    GnomeCanvasItem *rect;
    GnomeCanvasPoints *points;
    
    gnome_canvas_item_get_bounds(object, &x1, &y1, &x2, &y2);
    
    points = gnome_canvas_points_new(4);
    points->coords[0] = x1;
    points->coords[1] = y1;
    points->coords[2] = x2;
    points->coords[3] = y1;
    points->coords[4] = x2;
    points->coords[5] = y2;
    points->coords[6] = x1;
    points->coords[7] = y2;
    
    rect = gnome_canvas_item_new(group,
                                    gnome_canvas_polygon_get_type(),
                                    "points", points,
                                    "fill_color", NULL,
                                    "outline_color", "red",
                                    "width_pixels", 1,
                                    NULL);
    gnome_canvas_points_unref(points);
}

void 
bulk_select(GtabDoc *tab_doc, GnomeCanvasItem *select_rec)
{
    xmlNodePtr staff_verify;
    gdouble rect_x1, rect_y1, rect_x2, rect_y2;
    gdouble obj_x1, obj_y1, obj_x2, obj_y2;
    GnomeCanvasItem *select_me;
    GList* tmp;
    gint staff_holder;
    
    gnome_canvas_item_get_bounds(select_rec, &rect_x1, &rect_y1, 
                                                &rect_x2, &rect_y2);
    find_staff((rect_y2 + rect_y1)/2);
    staff_holder = current_staff;
    tab_doc->parent->clipboard_multi = TRUE;
    
    // insures good text lineup
    tab_doc->parent->clipboard_multi_start_x = (floor((rect_x1)/17.0))*17.0;      
    tab_doc->parent->clipboard_multi_start_y = clipboard_multi_find_y_offset(staff_holder);
    
    if (GNOME_IS_CANVAS_ITEM(tab_doc->highlights))    {
        gtk_object_destroy(GTK_OBJECT(tab_doc->highlights));
        tab_doc->highlights = NULL;
    }
    
    tab_doc->highlights = GNOME_CANVAS_GROUP
                    (gnome_canvas_item_new(tab_doc->staff_objects[current_staff],
                                            gnome_canvas_group_get_type(),
                                            NULL));
    tab_doc->obj_counter = g_list_first(tab_doc->obj_counter);
    tmp = tab_doc->obj_counter;      /* have to keep a pointer to the top of the list */
    tab_doc->parent->clipboard_objs = g_list_first(tab_doc->parent->clipboard_objs);
    if (g_list_length(tab_doc->parent->clipboard_objs) > 0) 
                    clear_clipboard(tab_doc->parent);
    
    // fprintf(stderr, "obj_counter length: %i\n", g_list_length(obj_counter));                                                                                                                            
    while (tab_doc->obj_counter != NULL)    {
        if (GNOME_IS_CANVAS_ITEM(tab_doc->obj_counter->data))    {
            select_me = GNOME_CANVAS_ITEM(tab_doc->obj_counter->data);
            gnome_canvas_item_get_bounds(select_me, &obj_x1, &obj_y1,
                                                    &obj_x2, &obj_y2);
            
            if (obj_x1 > rect_x1 && obj_x2 < rect_x2 &&
                (obj_y1+obj_y2)/2 > rect_y1 && (obj_y1+obj_y2)/2 < rect_y2 )    {
            
                staff_verify = (xmlNodePtr ) g_object_get_data
                                    (G_OBJECT(tab_doc->obj_counter->data), "node");
                if (staff_verify != NULL)    {
                    if (find_object_staff(staff_verify) == staff_holder)    {    
                        highlight_object(select_me, tab_doc->highlights);
                        tab_doc->parent->clipboard_objs = g_list_prepend(tab_doc->parent->clipboard_objs, 
                                                        (gpointer ) select_me);
                    }
                }
            }
        }
        
        tab_doc->obj_counter = g_list_next(tab_doc->obj_counter);
        
    }
    tab_doc->obj_counter = tmp;
    
}
    
double 
clipboard_multi_find_y_offset(gint staff_num)
{
    gdouble offset = 0;
    
    switch (staff_num)    {
        case 0:
            offset = 140.0;
            break;
        case 1:
            offset = 280.0;
            break;
        case 2:
            offset = 420.0;
            break;
        case 3:
            offset = 560.0;
            break;
        case 4:
            offset = 700.0;
            break;
        case 5:
            offset = 840.0;
            break;
    }
    
    return (offset);
}
        
gint 
find_object_staff(xmlNodePtr obj_node)    
{
    gint staff_num = 0;
    
    if (xmlIsBlankNode(obj_node) == 1) return(0);
        
    if (g_ascii_strcasecmp(obj_node->parent->name, "STAFF2") == 0) staff_num = 1;
    if (g_ascii_strcasecmp(obj_node->parent->name, "STAFF3") == 0) staff_num = 2;
    if (g_ascii_strcasecmp(obj_node->parent->name, "STAFF4") == 0) staff_num = 3;
    if (g_ascii_strcasecmp(obj_node->parent->name, "STAFF5") == 0) staff_num = 4;
    if (g_ascii_strcasecmp(obj_node->parent->name, "STAFF6") == 0) staff_num = 5;
    
    return(staff_num);
}

gchar* 
get_prop(xmlNodePtr node, const char* prop_name)
{
    char *ret, *val;
    
    if (xmlHasProp(node, prop_name)) {
        val = (char *) xmlGetProp (node, prop_name);
        if (val != NULL)    {
            ret = g_strdup (val);
            xmlFree (val);
            return ret;
        }
    }
    
    return NULL;
}

void refresh_fonts(GtabApp *app)
{
    GConfClient *client;
    
    if (app->tab_font != NULL) g_free(app->tab_font);
    if (app->tab_font_large != NULL) g_free(app->tab_font_large);
    if (app->tab_font_small != NULL) g_free(app->tab_font_small);
    if (app->tab_font_tiny != NULL) g_free(app->tab_font_tiny);
    if (app->chrd_bldr_font != NULL) g_free(app->chrd_bldr_font);
    if (app->chrd_bldr_font_small != NULL) g_free(app->chrd_bldr_font_small);
        
    client = gconf_client_get_default();
    
    app->tab_font = gconf_client_get_string(client, GCONF_TAB_FONT, NULL);
    app->tab_font_large = gconf_client_get_string(client, GCONF_TAB_FONT_LARGE, NULL);
    app->tab_font_small = gconf_client_get_string(client, GCONF_TAB_FONT_SMALL, NULL);
    app->tab_font_tiny = gconf_client_get_string(client, GCONF_TAB_FONT_TINY, NULL);
    app->chrd_bldr_font = gconf_client_get_string(client, GCONF_CHRD_BLDR_FONT, NULL);
    app->chrd_bldr_font_small = gconf_client_get_string(client, GCONF_CHRD_BLDR_FONT_SMALL, NULL);
    
}
    
void
take_care_of_business(GtabApp *app)
{
    gint i;
    GConfClient *client;
    gboolean     value;
    gint width, height;
            
    client = gconf_client_get_default();
    
    value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(app->btn_lib_chord));
    gtk_window_get_size(GTK_WINDOW(app->gnometab), &width, &height);
    
    gconf_client_set_bool(client, GCONF_CHORD_LIB_VISIBLE, value, NULL);
    gconf_client_set_int(client, GCONF_WINDOWHEIGHT, height, NULL);
    gconf_client_set_int(client, GCONF_WINDOWWIDTH, width, NULL);
    gconf_client_set_float(client, GCONF_ZOOMLEVEL, app->zoom_level, NULL);
    gconf_client_set_int(client, GCONF_HISTORY_N, app->history_n, NULL);
    gconf_client_set_list(client, GCONF_HISTORY_FILES, GCONF_VALUE_STRING, 
                                                app->history_files, NULL);
    
    if (((GtabChordLib *) app->chord_lib)->lib_doc) {
        i = xmlSaveFile(((GtabChordLib *) app->chord_lib)->filename, 
                    ((GtabChordLib *) app->chord_lib)->lib_doc);
    }
}
