/*
 * 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.
 *
 * See the COPYING file for license information.
 *
 * Guillaume Chazarain <guichaz@yahoo.fr>
 */

/******************************************
 * The vertical and horizontal scrollbars *
 ******************************************/

#include "gliv.h"
#include "scrollbars.h"
#include "options.h"
#include "gliv-image.h"
#include "windows.h"
#include "matrix.h"
#include "params.h"
#include "rendering.h"

extern rt_struct *rt;
extern options_struct *options;
extern GlivImage *current_image;

/* Horizontal Scrollbar. */
static GtkHScrollbar *hscroll;

/* Vertical Scrollbar. */
static GtkVScrollbar *vscroll;

gboolean toggle_scrollbars(void)
{
    GtkWidget *widgets[2];

    widgets[0] = GTK_WIDGET(hscroll);
    widgets[1] = GTK_WIDGET(vscroll);

    if (toggle_widgets(widgets, 2, &options->scrollbars) && options->scrollbars)
        update_scrollbars();

    return FALSE;
}

/* Update a given scrollbar. */
static void update_scroll(GtkScrollbar * scroll, gfloat min, gfloat max,
                          gfloat dim)
{
    GtkAdjustment *adj;
    gboolean update_needed = FALSE;
    gfloat previous;

    adj = gtk_range_get_adjustment(GTK_RANGE(scroll));

    /* Smallest length containing the image and the window = window U image. */
    previous = adj->lower;
    adj->lower = MIN(min, 0.0);
    update_needed = update_needed || !float_equal(previous, adj->lower);

    previous = adj->upper;
    adj->upper = MAX(max, dim);
    update_needed = update_needed || !float_equal(previous, adj->upper);

    /* Window size. */
    adj->page_size = dim;

    adj->step_increment = MOVE_OFFSET;
    adj->page_increment = dim;

    /* The offset is actually computed with adj->lower and adj->upper. */
    adj->value = 0.0;

    if (update_needed) {
        gtk_adjustment_changed(adj);
        gdk_window_process_updates(GTK_WIDGET(scroll)->window, FALSE);
    }
}

/* Update both scrollbars. */
void update_scrollbars(void)
{
    gfloat min_x, max_x, min_y, max_y;

    if (current_image == NULL || options->scrollbars == FALSE)
        return;

    get_matrix_bounding_box(&min_x, &max_x, &min_y, &max_y);

    update_scroll(GTK_SCROLLBAR(hscroll), min_x, max_x,
                  (gfloat) rt->wid_size->width);

    update_scroll(GTK_SCROLLBAR(vscroll), min_y, max_y,
                  (gfloat) rt->wid_size->height);
}

static gboolean scroll_val(GtkRange * range)
{
    gfloat offset;

    offset = -1.0 * gtk_range_get_value(range);

    if (range == GTK_RANGE(hscroll))
        matrix_move(offset, 0.0);
    else
        /* range == GTK_RANGE(vscroll) */
        matrix_move(0.0, offset);

    refresh(REFRESH_BURST | APPEND_HISTORY);
    update_scrollbars();
    return FALSE;
}

/* Called during the initialization to build the two scrollbars. */
GtkWidget *get_new_scrollbar(gboolean horizontal)
{
    GtkRange *range;

    if (horizontal) {
        range = GTK_RANGE(gtk_hscrollbar_new(NULL));
        hscroll = GTK_HSCROLLBAR(range);
    } else {
        range = GTK_RANGE(gtk_vscrollbar_new(NULL));
        vscroll = GTK_VSCROLLBAR(range);
    }

    gtk_range_set_update_policy(range, GTK_UPDATE_CONTINUOUS);

    g_signal_connect(range, "value-changed", G_CALLBACK(scroll_val), NULL);

    return GTK_WIDGET(range);
}

void hide_scrollbars(void)
{
    gtk_widget_hide(GTK_WIDGET(hscroll));
    gtk_widget_hide(GTK_WIDGET(vscroll));
}
