/* 
   PXKScrollButton.m

   Copyright (C) 1996 Free Software Foundation, Inc.

   Author:  Pascal Forget <pascal@wsc.com>
   Date: October 1995
   
   This file is part of the GNUstep GUI X/DPS Backend.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.
   
   This library 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
   Library General Public License for more details.

   If you are interested in a warranty or support for this source code,
   contact Scott Christley <scottc@net-community.com> for more information.
   
   You should have received a copy of the GNU Library General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ 

#include <gnustep/xdps/PXKScrollButton.h>
#include <gnustep/xdps/PXKScroller.h>
#include <gnustep/xdps/PXKImage.h>

@implementation PXKScrollButton

- adjustLocation;
{
    float min = [(PXKScroller *)super_view minValue];
    float max = [(PXKScroller *)super_view maxValue];
    float cur = [(PXKScroller *)super_view currentValue];

    if (vertical) {
	frame.origin.y = (scrollArea.origin.y +
			  scrollArea.size.height) * cur / (max-min) -
			 (frame.size.height/2.0);
    } else {
	frame.origin.x = (scrollArea.origin.x +
			  scrollArea.size.width) * cur / (max-min) -
			 (frame.size.width/2.0);
    }

#if 0
    if (vertical) {
	fprintf(stdout, "after adjusting location x: %d y: %d w: %d h: %d\n",
		frame.origin.x, frame.origin.y,
		frame.size.width, frame.size.height);
    }
#endif
    
    [self moveTo:frame.origin.x :frame.origin.y];

    return self;
}

- adjustSize;
{
    if ((vertical = [super_view vertical]) == YES) {

//	fprintf(stdout, "adjustSize Y scroller with ratio: %1.3f\n",ratio);
	frame.origin.y = 0;
	frame.origin.x = 2;
	frame.size.width = scrollArea.size.width;
	frame.size.height = ((float)scrollArea.size.height) * ratio;
    } else {

//	fprintf(stdout, "adjustSize X scroller with ratio: %1.3f\n",ratio);

	frame.origin.x = 0;
	frame.origin.y = 2;
	frame.size.height = scrollArea.size.height;
	frame.size.width = ((float)scrollArea.size.width) * ratio;
    }

    if (frame.size.height < PXK_ARROW_SIZE) {
	frame.size.height = PXK_ARROW_SIZE;
    }
    if (frame.size.width < PXK_ARROW_SIZE) {
	frame.size.width = PXK_ARROW_SIZE;
    }	
    
#if 0
    if (vertical) {
	fprintf(stdout, "after adjusting size x: %d y: %d w: %d h: %d\n",
		frame.origin.x, frame.origin.y,
		frame.size.width, frame.size.height);
    }
#endif    
    
    [self setFrame:frame];
    
#if 0
    fprintf(stdout, "New size: x: %d y: %d w: %d h: %d\n",
	    frame.origin.x,
	    frame.origin.y,
	    frame.size.width,
	    frame.size.height);
#endif

    /* This line just for testing purposes */
    //[self display];
    
    //puts("after adjustSize");
    
    return self;
}


#if 1
- setRatio:(float)r;
{
    if ((r >= 0.0) && (r <= 1.0)) {
	ratio = r;
	[self adjustSize];
	return self;
    }
    return nil;
}
#else
- setRatio:(float)r;
{
    if ((ratio >= 0.0) && (ratio <= 1.0)) {
	ratio = r;
	[self adjustSize];
	return self;
    }
    return nil;
}
#endif

- setScrollArea:(NSRect)area;
{
    NSRect r = area;

    scrollArea = r;

#if 0    
    if (vertical) {
	fprintf(stdout, "Scroll area: %d %d %d %d\n",
		scrollArea.origin.x, scrollArea.origin.y,
		scrollArea.size.width, scrollArea.size.height);
    }
#endif    
    
    [self adjustSize];
    return self;
}

- init;
{
    [super init];

#if 0
    if (title) {
	free(title);
	title = (char *)NULL;
    }
#endif

    //    continuous = YES;
    //    type = PXK_MOMENTARY_CHANGE_MODE;
    //    state = 0;
    ratio = 1.0;
    
    [self setTarget:self];
    [self setAction:@selector(updateScroller)];    
    
    [self setImage:[PXKImage imageNamed:"pxkDimple"]];

    return self;
}

- display;
{
    [self adjustLocation];
    [super display];
    [self drawSelf];
    return self;
}

- mouseDown:(XEvent *)e;
{
#if 0

    fprintf(stdout, "mouse down\n");    
//    if (type == PXK_TOGGLE_MODE) {
    if (NO) {
	fprintf(stdout, "PXKButton mouseDown: (toggle mode)\n");
	[self toggleState];
	[self sendAction];
    } else {
	fprintf(stdout, "PXKButton mouseDown: (!toggle mode)\n");	
	state = 1;
    }
#endif
    [self display];
    return self;
}

- mouseDragged:(XEvent *)e;
{
    XEvent event = *e;
    NSPoint location;
    Window root, child;
    int root_x, root_y, pos_x, pos_y;
    unsigned int keys_buttons;
    NSPoint hotSpot;
    
    hotSpot.x = -1;
    hotSpot.y = -1;
    
    location.x = event.xmotion.x;
    location.y = event.xmotion.y;

    while (1) {

	XNextEvent(pxkDisplay, &event);
	
	if (event.type == MotionNotify) {

	    location.x = event.xmotion.x;
	    location.y = event.xmotion.y;

	    if (!XQueryPointer(pxkDisplay, event.xmotion.window,
			       &root, &child, &root_x, &root_y, &pos_x,
			       &pos_y, &keys_buttons))
		/* pointer is on other screen */
		break;

	    if (child == [super_view xWindow]) {
		location.x = pos_x;
		location.y = pos_y;
	    } else {
		location.x = pos_x + frame.origin.x;
		location.y = pos_y + frame.origin.y;
	    }

	    if ((location.x >= frame.origin.x) &&
		(location.x < (frame.origin.x + frame.size.width)) &&
		(hotSpot.x == -1))
	    {
		hotSpot.x = location.x - frame.origin.x;
	    } else {
		hotSpot.x = -1; /* invalid */
	    }
	    
	    if ((location.y >= frame.origin.y) &&
		(location.y < (frame.origin.y + frame.size.height)) &&
		(hotSpot.y == -1))
	    {
		hotSpot.y = location.y - frame.origin.x;
	    } else {
		hotSpot.y = -1; /* invalid */
	    }

	    /* The following code, commented out, is seriously bogus. */
#if 0	    
	    if (hotSpot.x > 0) {
		location.x -= hotSpot.x;
	    }

	    if (hotSpot.y > 0) {
		location.y -= hotSpot.y;
	    }
#endif
    	    
	    [self moveTo:location.x :location.y];

	    if ([self isContinuous]) {
		[self sendAction];
	    }
	    continue;
	}
	
	if (![self isContinuous]) {
	    [self sendAction];
	}
	
	break;
    }

    return self;
}

- mouseUp:(XEvent *)e;
{
#if 0    
    fprintf(stdout, "mouse up\n");
//    if (type == PXK_MOMENTARY_PUSH_MODE) {
    if (YES) {
	fprintf(stdout, "PXKButton mouseUp: (momentary push mode)\n");
	state = 0;
	[self display];
	[self sendAction];
    }
#endif    
    return self;
}

/*
 * This method overrides the PXKView's implementation.
 * Since a scroll button can only move within the
 * boundaries of the scroller's scroll area,
 * this implementation of moveTo:: places the button
 * as close as possible to the desired location.
 */

- moveTo:(int)x :(int)y;
{
    if (vertical) {
	if (y >= scrollArea.origin.y) {
	    if (y < (scrollArea.origin.y +
		     scrollArea.size.height -
		     frame.size.height))
	    {
		frame.origin.y = y; /* Valid value */
	    } else {
		/* Max */
		frame.origin.y = scrollArea.origin.y +
				 scrollArea.size.height -
				 frame.size.height;
	    }
	} else {
	    frame.origin.y = scrollArea.origin.y; /* Min */
	}
    } else {
	if (scrollArea.origin.x < x) {
	    if ((scrollArea.origin.x + scrollArea.size.width) >
		(x+frame.size.width)) {
		frame.origin.x = x; /* Valid value */
	    } else {
		/* Max */
		frame.origin.x = scrollArea.origin.x +
				 scrollArea.size.width -
				 frame.size.width;
	    }
	} else {
	    frame.origin.x = scrollArea.origin.x; /* Min */
	}
    }
    [self moveBy:0:0];
    return self;
}

- setFrame:(NSRect)newFrame;
{
    NSRect r = newFrame;

    [super setFrame:r];
    
    if ([(PXKScroller *)super_view vertical]) {
	vertical = YES;
    } else {
	vertical = NO;
    }

    return self;
}

- updateScroller;
{
    float relativePosition;
    float min = [(PXKScroller *)super_view minValue];
    float max = [(PXKScroller *)super_view maxValue];
    float newValue;
    float frameMin;
    float frameMax;
    
    if (vertical) {
	frameMin = scrollArea.origin.y;
	frameMax = scrollArea.origin.y + scrollArea.size.height -
		   frame.size.height;

	relativePosition = (frame.origin.y-scrollArea.origin.y)/
			   (frameMax-frameMin);	
    } else {
	frameMin = scrollArea.origin.x + frame.size.width/2.0;
	frameMax = scrollArea.origin.x + scrollArea.size.width -
		   frame.size.width/2.0;

	relativePosition = (frame.origin.x-scrollArea.origin.x)/
			   (frameMax-frameMin);
    }
#if 0
    fprintf(stdout, "rel pos: %1.4f\n", relativePosition);
#endif    
    newValue = min +(max-min)*relativePosition;
    [(PXKScroller *)super_view setCurrentValue:newValue];
    return self;
}

@end
