/***************************************************************************/
/***************************************************************************/
/*                                                                         */
/*   (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 <Xm/Xm.h>
#include <sys/param.h>
#include "xdir.h"

#define INTERVAL    50L

static int pivot_x;
static int pivot_y;
static int corner_x;
static int corner_y;
static int upper_left_x;
static int upper_left_y;
static int lower_right_x;
static int lower_right_y;
static struct dirwin_st *toggle_dirwin;
static XtIntervalId toggle_rect_timer_id;

extern Display *display;
extern Window root_window;
extern GC gc_rect;
extern XtAppContext app;

void adjust_selection_states();
void set_toggle_rect_timer();

/*
 * point_in_drawing_area - Returns true if virtual point (x,y) is in the 
 *                         drawing  area's window.
 */
point_in_drawing_area(dirwin, x, y, above, below, to_left, to_right)
struct dirwin_st *dirwin;
int x;
int y;
int *above;
int *below;
int *to_left;
int *to_right;
{
	Window child;
	int x_da;
	int y_da;
	int x_point;
	int y_point;
	Dimension drawing_area_width;
	Dimension drawing_area_height;

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

	/* Get coordinates of drawing area's origin */
	XTranslateCoordinates(display, XtWindow(dirwin->w_drawingArea),
		root_window, 0, 0, &x_da, &y_da, &child);
	
	/* Convert point into global coordinates */
	XTranslateCoordinates(display, XtWindow(dirwin->w_drawingArea),
		root_window, actual_x(dirwin, x), actual_y(dirwin, y), &x_point,
		&y_point, &child);

	/* Is point in drawing area window? */
	*to_left = x_point < x_da;
	*to_right = x_point >= (int)(x_da+drawing_area_width);
	*above = y_point < y_da;
	*below = y_point >= (int)(y_da+drawing_area_height);
	if (*to_left || *to_right || *above || *below)
		return False;
	else
		return True;
}


void
init_toggle_rect(dirwin, x, y)
struct dirwin_st *dirwin;
int x;
int y;
{
	int i;

	/* Clear error flag */
	raise_okflag();

	/* Remember which dirwin */
	toggle_dirwin = dirwin;

	/* First clear other hosts' selected directory entries */
	if (!toggle_dirwin->has_selection) {
		clear_selected_entries();
		toggle_dirwin->has_selection = True;
	}

	/* Draw rectangle */
	pivot_x = x;
	pivot_y = y;
	corner_x = x;
	corner_y = y;
	XDrawRectangle(display, XtWindow(toggle_dirwin->w_drawingArea), gc_rect,
		actual_x(toggle_dirwin, x), actual_y(toggle_dirwin, y), 0, 0);

	/* Remember original selection states of entries */
	for (i=0; i<toggle_dirwin->nentries; i++)
		toggle_dirwin->entries[i].original_state
			= toggle_dirwin->entries[i].state;
}


void
draw_toggle_rect()
{
	upper_left_x = MIN(pivot_x, corner_x);
	upper_left_y = MIN(pivot_y, corner_y);
	lower_right_x = MAX(pivot_x, corner_x);
	lower_right_y = MAX(pivot_y, corner_y);
	XDrawRectangle(display, XtWindow(toggle_dirwin->w_drawingArea), gc_rect,
		actual_x(toggle_dirwin, upper_left_x),
		actual_y(toggle_dirwin, upper_left_y),
		lower_right_x-upper_left_x, lower_right_y-upper_left_y);
}


void
move_toggle_rect(x, y)
int x;
int y;
{
	int above;
	int below;
	int to_left;
	int to_right;
	int in_drawing_area;

	/* This is slow, so don't do it between erasing and redrawing rect */
	in_drawing_area = point_in_drawing_area(toggle_dirwin, x, y, &above, &below,
		&to_left, &to_right);

	/* Erase previous rectangle */
	draw_toggle_rect();
	corner_x = x;
	corner_y = y;

	/* Scroll if necessary */
	if (!in_drawing_area) {
		if (above)
			scroll_up(toggle_dirwin);
		else if (below)
			scroll_down(toggle_dirwin);
		if (to_left)
			scroll_left(toggle_dirwin);
		else if (to_right)
			scroll_right(toggle_dirwin);
	}

	/* Only directory entries in the toggle rectangle should be toggled */
	adjust_selection_states(toggle_dirwin);

	/* Draw new rectangle */
	draw_toggle_rect();
}


/*
 * adjust_selection_states - Sets the "state" field of each directory entry
 *                           in the toggle  rectangle to the opposite of
 *                           what it is in the field "original_state".
 */
void
adjust_selection_states(dirwin)
struct dirwin_st *dirwin;
{
	int i;
	int need_to_toggle;
	int row;

	for (i=0; i<dirwin->nentries; i++) {
		need_to_toggle = False;
		if (entry_in_toggle_rect(&dirwin->entries[i])) {
			if (dirwin->entries[i].state == dirwin->entries[i].original_state)
				need_to_toggle = True;
		} else {
			if (dirwin->entries[i].state != dirwin->entries[i].original_state)
				need_to_toggle = True;
		}
		if (need_to_toggle) {
			if (dirwin->entries[i].state == UNSELECTED)
				dirwin->entries[i].state = SELECTED;
			else
				dirwin->entries[i].state = UNSELECTED;
			row = dirwin->entries[i].indx%toggle_dirwin->nrows;
			if (row >= toggle_dirwin->first_visible_row &&
					row < toggle_dirwin->first_visible_row
					+toggle_dirwin->nrows_visible)
				draw_entry(&dirwin->entries[i]);
		}
	}
}


/*
 * entry_in_toggle_rect - Returns True if the directory entry specified
 *                        by "einfo" is in the toggle rectangle.
 *
 */
entry_in_toggle_rect(einfo)
struct entry_info *einfo;
{
	int col;
	int row;
	int x;
	int y;

	switch (toggle_dirwin->layout) {
	case TABULAR:
	case ICONIC:
		col = einfo->indx/toggle_dirwin->nrows;
		row = einfo->indx%toggle_dirwin->nrows;
		x = HMARGIN+col*(toggle_dirwin->max_entry_width+HSPACING);
		y = row*(toggle_dirwin->entry_height+VSPACING);
		break;
	case TREE:
		x = HMARGIN+einfo->level*INDENT+CWIDTH+CMARGIN;
		y = einfo->indx*(toggle_dirwin->entry_height+VSPACING);
		break;
	case FULL_INFO:
		x = HMARGIN;
		y = einfo->indx*(toggle_dirwin->entry_height+VSPACING);
		break;
	}
	if (x+einfo->width < upper_left_x ||
			x > lower_right_x ||
			y+einfo->dirwin->entry_height < upper_left_y ||
			y > lower_right_y)
		return False;
	else
		return True;
}


void
remove_toggle_rect()
{
	/* Erase previous rectangle */
	draw_toggle_rect();

	update_dir_controls();
}


void
cb_toggle_rect(client_data, id)
XtPointer client_data;
XtIntervalId *id;
{
	Window root;
	Window child;
	int root_x;
	int root_y;
	int win_x;
	int win_y;
	unsigned int keys_buttons;

	if (XQueryPointer(display, XtWindow(toggle_dirwin->w_drawingArea), &root,
			&child, &root_x, &root_y, &win_x, &win_y, &keys_buttons))
		move_toggle_rect(virtual_x(toggle_dirwin, win_x), 
			virtual_y(toggle_dirwin, win_y));

	set_toggle_rect_timer();
}


void
set_toggle_rect_timer()
{
	toggle_rect_timer_id = XtAppAddTimeOut(app, INTERVAL,
		(XtTimerCallbackProc)cb_toggle_rect, NULL);
}


void
unset_toggle_rect_timer()
{
	XtRemoveTimeOut(toggle_rect_timer_id);
}



syntax highlighted by Code2HTML, v. 0.9.1