/***************************************************************************/
/***************************************************************************/
/*                                                                         */
/*   (c) 1995-1999.  The Regents of the University of California.  All     */
/*   rights reserved.                                                      */
/*                                                                         */
/*   This work was produced at the University of California, Lawrence      */
/*   Livermore National Laboratory (UC LLNL) under contract no.            */
/*   W-7405-ENG-48 (Contract 48) between the U.S. Department of Energy     */
/*   (DOE) and The Regents of the University of California (University)    */
/*   for the operation of UC LLNL.  Copyright is reserved to the           */
/*   University for purposes of controlled dissemination,                  */
/*   commercialization through formal licensing, or other disposition      */
/*   under terms of Contract 48; DOE policies, regulations and orders;     */
/*   and U.S. statutes.  The rights of the Federal Government are          */
/*   reserved under Contract 48 subject to the restrictions agreed upon    */
/*   by the DOE and University.                                            */
/*                                                                         */
/*                                                                         */
/*                              DISCLAIMER                                 */
/*                                                                         */
/*   This software was prepared as an account of work sponsored by an      */
/*   agency of the United States Government.  Neither the United States    */
/*   Government nor the University of California nor any of their          */
/*   employees, makes any warranty, express or implied, or assumes any     */
/*   liability or responsibility for the accuracy, completeness, or        */
/*   usefulness of any information, apparatus, product, or process         */
/*   disclosed, or represents that its specific commercial products,       */
/*   process, or service by trade name, trademark, manufacturer, or        */
/*   otherwise, does not necessarily constitute or imply its               */
/*   endorsement, recommendation, or favoring by the United States         */
/*   Government or the University of California. The views and opinions    */
/*   of the authors expressed herein do not necessarily state or reflect   */
/*   those of the United States Government or the University of            */
/*   California, and shall not be used for advertising or product          */
/*   endorsement purposes.                                                 */
/*                                                                         */
/*   Permission to use, copy, modify and distribute this software and its  */
/*   documentation for any non-commercial purpose, without fee, is         */
/*   hereby granted, provided that the above copyright notice and this     */
/*   permission notice appear in all copies of the software and            */
/*   supporting documentation, and that all UC LLNL identification in      */
/*   the user interface remain unchanged.  The title to copyright LLNL     */
/*   XDIR shall at all times remain with The Regents of the University     */
/*   of California and users agree to preserve same. Users seeking the     */
/*   right to make derivative works with LLNL XDIR for commercial          */
/*   purposes may obtain a license from the Lawrence Livermore National    */
/*   Laboratory's Technology Transfer Office, P.O. Box 808, L-795,         */
/*   Livermore, CA 94550.                                                  */
/*                                                                         */
/***************************************************************************/
/***************************************************************************/

#include <sys/param.h>
#include <Xm/Xm.h>
#include "xdir.h"

#define HPAGEINCREMENT 4

extern Display *display;
extern GC gcv1;
extern int safe_to_redraw;

void scroll_vertical();
void scroll_horizontal();


void
cb_scroll_vertical(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
	struct dirwin_st *dirwin = (struct dirwin_st *)client_data;
	XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *)call_data;

	/* Make sure that the data structures are consistent */
	if (!safe_to_redraw)
		return;

	scroll_vertical(dirwin, cbs->value);
}


void
scroll_down(dirwin)
struct dirwin_st *dirwin;
{
	Widget w_vertical_sb;
	int value;

    XtVaGetValues(dirwin->w_scrolledWindow, XmNverticalScrollBar,
		&w_vertical_sb, NULL);
    XtVaGetValues(w_vertical_sb, XmNvalue, &value, NULL);
	scroll_vertical(dirwin, value+1);
}


void
scroll_up(dirwin)
struct dirwin_st *dirwin;
{
	Widget w_vertical_sb;
	int value;

    XtVaGetValues(dirwin->w_scrolledWindow, XmNverticalScrollBar,
		&w_vertical_sb, NULL);
    XtVaGetValues(w_vertical_sb, XmNvalue, &value, NULL);
	scroll_vertical(dirwin, value-1);
}


void
scroll_vertical(dirwin, value)
struct dirwin_st *dirwin;
int value;
{
	Dimension drawing_area_width;
	int width;
	int height;
	int x;
	int y;
	int offset;
	int src_x;
	int src_y;
	int dest_x;
	int dest_y;
	int minimum;
	int maximum;
	int slider_size;
	Widget w_vertical_sb;

	/* If no change, or value out of range, nothing to do */
    XtVaGetValues(dirwin->w_scrolledWindow, XmNverticalScrollBar,
		&w_vertical_sb, NULL);
    XtVaGetValues(w_vertical_sb,
		XmNminimum,			&minimum,
        XmNmaximum,         &maximum,
        XmNsliderSize,      &slider_size,
        NULL
    );
	if (value == dirwin->first_visible_row || value < minimum 
			|| value > maximum-slider_size)
		return;
	XtVaSetValues(w_vertical_sb, XmNvalue, value, NULL);

	/* If no overlap, redraw entire window */
	if (value >= dirwin->first_visible_row+dirwin->nrows_visible ||
			value+dirwin->nrows_visible <= dirwin->first_visible_row) {
		dirwin->first_visible_row = value;
		redraw_entire_dir(dirwin);
		return;
	}

	/* There is overlap.  Block copy overlap.  Explicitly redraw rest */
	XtVaGetValues(dirwin->w_drawingArea, XmNwidth, &drawing_area_width, NULL);
	if (value > dirwin->first_visible_row) {
		offset = value-dirwin->first_visible_row;
		src_x = 0;
		src_y = VTMARGIN+offset*(dirwin->entry_height+VSPACING);
		dest_x = 0;
		dest_y = VTMARGIN;
		width = drawing_area_width;
		height = (dirwin->nrows_visible-offset)
			*(dirwin->entry_height+VSPACING)-VSPACING;
		XSync(display, 0);
		XCopyArea(display, XtWindow(dirwin->w_drawingArea),
			XtWindow(dirwin->w_drawingArea), gcv1, src_x, src_y, width, height,
			dest_x, dest_y);
		dirwin->first_visible_row = value;
		x = virtual_x(dirwin, 0);
		y = virtual_y(dirwin, VTMARGIN+(dirwin->nrows_visible-offset)
			*(dirwin->entry_height+VSPACING));
		width = drawing_area_width;
		height = offset*(dirwin->entry_height+VSPACING)-VSPACING;
		redraw_dir(dirwin, x, y, width, height, True, NULL, 0);
	} else {
		offset = dirwin->first_visible_row-value;
		src_x = 0;
		src_y = VTMARGIN;
		dest_x = 0;
		dest_y = VTMARGIN+offset*(dirwin->entry_height+VSPACING);
		width = drawing_area_width;
		height = (dirwin->nrows_visible-offset)
			*(dirwin->entry_height+VSPACING)-VSPACING;
		XSync(display, 0);
		XCopyArea(display, XtWindow(dirwin->w_drawingArea),
			XtWindow(dirwin->w_drawingArea), gcv1, src_x, src_y, width, height,
			dest_x, dest_y);
		dirwin->first_visible_row = value;
		x = virtual_x(dirwin, 0);
		y = virtual_y(dirwin, 0);
		width = drawing_area_width;
		height = VTMARGIN+offset*(dirwin->entry_height+VSPACING);
		redraw_dir(dirwin, x, y, width, height, True, NULL, 0);
	}
}


void
cb_scroll_horizontal(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
	struct dirwin_st *dirwin = (struct dirwin_st *)client_data;
	XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *)call_data;

	/* Make sure that the data structures are consistent */
	if (!safe_to_redraw)
		return;

	scroll_horizontal(dirwin, cbs->value);
}


void
scroll_right(dirwin)
struct dirwin_st *dirwin;
{
	Widget w_horizontal_sb;
	int value;

    XtVaGetValues(dirwin->w_scrolledWindow, XmNhorizontalScrollBar,
		&w_horizontal_sb, NULL);
    XtVaGetValues(w_horizontal_sb, XmNvalue, &value, NULL);
	scroll_horizontal(dirwin, value+1);
}


void
scroll_left(dirwin)
struct dirwin_st *dirwin;
{
	Widget w_horizontal_sb;
	int value;

    XtVaGetValues(dirwin->w_scrolledWindow, XmNhorizontalScrollBar,
		&w_horizontal_sb, NULL);
    XtVaGetValues(w_horizontal_sb, XmNvalue, &value, NULL);
	scroll_horizontal(dirwin, value-1);
}


void
scroll_horizontal(dirwin, value)
struct dirwin_st *dirwin;
int value;
{
	Dimension drawing_area_width;
	Dimension drawing_area_height;
	int width;
	int height;
	int x;
	int y;
	int offset;
	int src_x;
	int src_y;
	int dest_x;
	int dest_y;
	XRectangle rect;
	int minimum;
	int maximum;
	int slider_size;
	Widget w_horizontal_sb;

	/* If no change, or value out of range, nothing to do */
    XtVaGetValues(dirwin->w_scrolledWindow, XmNhorizontalScrollBar,
		&w_horizontal_sb, NULL);
    XtVaGetValues(w_horizontal_sb,
		XmNminimum,			&minimum,
        XmNmaximum,         &maximum,
        XmNsliderSize,      &slider_size,
        NULL
    );
	if (value == dirwin->first_visible_hincrement || value < minimum 
			|| value > maximum-slider_size)
		return;
	XtVaSetValues(w_horizontal_sb, XmNvalue, value, NULL);

	/* Get drawing area dimensions */
	XtVaGetValues(dirwin->w_drawingArea,
		XmNwidth,	&drawing_area_width,
		XmNheight,	&drawing_area_height,
		NULL
	);

	/* If no overlap, redraw entire window */
	if (value >= dirwin->first_visible_hincrement
			+dirwin->nhincrements_visible ||
			dirwin->nhincrements_visible < dirwin->first_visible_hincrement) {
		redraw_entire_dir(dirwin);
		dirwin->first_visible_hincrement = value;
		goto clear_margins;
	}

	/* There is overlap.  Block copy overlap.  Explicitly redraw rest */
	if (value > dirwin->first_visible_hincrement) {
		offset = value-dirwin->first_visible_hincrement;
		src_x = offset*HINCREMENT;
		src_y = 0;
		dest_x = 0;
		dest_y = 0;
		width = drawing_area_width-src_x;
		height = drawing_area_height;
		XSync(display, 0);
		XCopyArea(display, XtWindow(dirwin->w_drawingArea),
			XtWindow(dirwin->w_drawingArea), gcv1, src_x, src_y, width, height,
			dest_x, dest_y);
		rect.x = width;
		rect.y = 0;
		rect.width = src_x;
		rect.height = drawing_area_height;
		x = virtual_x(dirwin, width);
		y = virtual_y(dirwin, 0);
		width = src_x;
		height = drawing_area_height;
		redraw_dir(dirwin, x, y, width, height, True, &rect, 1);
	} else {
		offset = dirwin->first_visible_hincrement-value;
		src_x = 0;
		src_y = 0;
		dest_x = offset*HINCREMENT;
		dest_y = 0;
		width = drawing_area_width-dest_x;
		height = drawing_area_height;
		XSync(display, 0);
		XCopyArea(display, XtWindow(dirwin->w_drawingArea),
			XtWindow(dirwin->w_drawingArea), gcv1, src_x, src_y, width, height,
			dest_x, dest_y);
		rect.x = 0;
		rect.y = 0;
		rect.width = dest_x;
		rect.height = drawing_area_height;
		x = virtual_x(dirwin, 0);
		y = virtual_y(dirwin, 0);
		width = dest_x;
		height = drawing_area_height;
		redraw_dir(dirwin, x, y, width, height, True, &rect, 1);
	}
	dirwin->first_visible_hincrement = value;

clear_margins:

	/* Clear left margin */
	if (value*HINCREMENT < HMARGIN) {
		x = 0;
		y = 0;
		width = HMARGIN-value*HINCREMENT;
		height = drawing_area_height;
		XClearArea(display, XtWindow(dirwin->w_drawingArea), x, y, width,
			height, False);
	}

	/* Clear right margin */
	if (dirwin->virtual_width-value*HINCREMENT-HMARGIN
			< (int)drawing_area_width) {
		x = dirwin->virtual_width-value*HINCREMENT-HMARGIN;
		y = 0;
		width = drawing_area_width-x;
		height = drawing_area_height;
		XClearArea(display, XtWindow(dirwin->w_drawingArea), x, y, width,
			height, False);
	}
}


/*
 * reset_scrollbars - Set the display's scrollbars to values appropriate
 *                    to its contents.  Set vertical scrollbar value to
 *                    "vert_value".  Set to -1 to retain current value.
 *                    Set horizontal scrollbar value to "horiz_value".
 *                    Set to -1 to retain current value.
 */
void
reset_scrollbars(dirwin, horiz_value, vert_value)
struct dirwin_st *dirwin;
int horiz_value;
int vert_value;
{
    Widget w_vertical_sb;
    Widget w_horizontal_sb;
    int value;
    int slider_size;
    int nhincrements;
    int nhincrements_visible;
	Dimension drawing_area_width;

    XtVaGetValues(dirwin->w_scrolledWindow,
        XmNhorizontalScrollBar, &w_horizontal_sb,
        XmNverticalScrollBar,   &w_vertical_sb,
        NULL
    );

    /* Adjust vertical scrollbar parameters */
    if (XtIsManaged(w_vertical_sb)) {
		if (vert_value == -1)
        	XtVaGetValues(w_vertical_sb, XmNvalue, &value, NULL);
		else
			value = vert_value;
		if ((dirwin->nrows < value+dirwin->nrows_visible-1) && value)
			value = MAX(0, dirwin->nrows-dirwin->nrows_visible);
        slider_size = MIN(dirwin->nrows_visible, dirwin->nrows);
        XtVaSetValues(w_vertical_sb,
            XmNmaximum,         MAX(dirwin->nrows, 1),
            XmNsliderSize,      MAX(slider_size, 1),
            XmNpageIncrement,   MAX(dirwin->nrows_visible-1, 1),
            XmNvalue,           MIN(value, dirwin->nrows-slider_size),
            NULL
        );
        XtVaGetValues(w_vertical_sb, XmNvalue, &dirwin->first_visible_row,
            NULL);
    } else
        dirwin->first_visible_row = 0;

    /* Adjust horizontal scrollbar parameters */
    if (XtIsManaged(w_horizontal_sb)) {
		if (horiz_value == -1)
        	XtVaGetValues(w_horizontal_sb, XmNvalue, &value, NULL);
		else
			value = horiz_value;
        nhincrements = (dirwin->virtual_width+HINCREMENT-1)/HINCREMENT;
		XtVaGetValues(dirwin->w_drawingArea, XmNwidth, &drawing_area_width,
			NULL);
        nhincrements_visible =(int)(drawing_area_width+HINCREMENT-1)/HINCREMENT;
        slider_size = MIN(nhincrements_visible, nhincrements);
        XtVaSetValues(w_horizontal_sb,
            XmNmaximum,         MAX(nhincrements, 1),
            XmNsliderSize,      MAX(slider_size, 1),
            XmNpageIncrement,   MAX(HPAGEINCREMENT, 1),
            XmNvalue,           MIN(value, nhincrements-slider_size),
            NULL
        );
        XtVaGetValues(w_horizontal_sb, XmNvalue,
            &dirwin->first_visible_hincrement, NULL);
        dirwin->nhincrements = nhincrements;
        dirwin->nhincrements_visible = nhincrements_visible;
    } else
        dirwin->first_visible_hincrement = 0;
}


void
scroll_entry_into_view(einfo)
struct entry_info *einfo;
{
	struct dirwin_st *dirwin = einfo->dirwin;
	int row = einfo->indx%dirwin->nrows;
	int value;
	int x;
	int col;
	int left_da_x;
	int right_da_x;
	Dimension drawing_area_width;
	int width;

	/* Scroll vertically, if necessary */
    if (row < dirwin->first_visible_row)
		scroll_vertical(dirwin, row);
    else if (row >= dirwin->first_visible_row+dirwin->nrows_visible)
		scroll_vertical(dirwin, row-dirwin->nrows_visible+1);

	/* Scroll horizontally, if necessary */
    switch (dirwin->layout) {
    case TABULAR:
    case ICONIC:
        col = einfo->indx/dirwin->nrows;
        x = HMARGIN+col*(dirwin->max_entry_width+HSPACING);
		width = einfo->width;
        break;
    case TREE:
        x = HMARGIN+einfo->level*INDENT;
		width = CWIDTH+CMARGIN+einfo->width;
        break;
    case FULL_INFO:
        x = HMARGIN;
		width = einfo->width;
        break;
    }
	XtVaGetValues(dirwin->w_drawingArea, XmNwidth, &drawing_area_width, NULL);
	left_da_x = virtual_x(dirwin, 0);
	right_da_x = left_da_x+drawing_area_width;
	if (x < left_da_x) {
		if (dirwin->layout == TREE && einfo->level != 0)
			value = (x-HMARGIN)/HINCREMENT;
		else
			value = 0;
		scroll_horizontal(dirwin, value);
	} else if (x+width > right_da_x) {
		if (dirwin->layout == TREE && einfo->level != 0)
			value = MAX(x, right_da_x-width-HMARGIN)/HINCREMENT;
		else
			value = 0;
		scroll_horizontal(dirwin, value);
	}
}



syntax highlighted by Code2HTML, v. 0.9.1