/* widget-slider.m,
 */

#include <allegro.h>
#include "widget-slider.h"


/*------------------------------------------------------------*/
/* Abstract Slider Class.                                     */
/*------------------------------------------------------------*/


@implementation Slider
- (id) init
{
    [super init];
    draw_background = YES;
    return self;
}

- (id) setSliderPrecision:(int)precision { slider_precision = MAX(1, precision); return self; }
- (id) setHandleW:(int)w_ { handle_w = MAX(1, w_); return self; }
- (id) setHandleH:(int)h_ { handle_h = MAX(1, h_); return self; }

- (id) setHandlePosition:(int)pos
{
    int old_pos = handle_pos;
    handle_pos = MID(0, pos, slider_precision - 1);
    if (handle_pos != old_pos)
	flags |= FLAG_DIRTY;
    return self; 
}

- (int) sliderHandlePosition { return handle_pos; }
- (int) sliderPrecision { return slider_precision-1; }
- (int) sliderLength { return [self sliderMax] - [self sliderMin]; }

- (double) sliderStepSize
{ 
    int sl = [self sliderLength];
    if (slider_precision <= 1)
	return sl;
    else if ((slider_precision - 1) < sl)
	return sl / (slider_precision - 1);
    else			/* 1px = more than 1 slider pos. */
	return 10.0;
}

- (id) setDrawBackground:(BOOL)draw { draw_background = draw; return self; }
- (id) setPushedProc:(int (*)(Widget *, int, int))proc { pushed_proc = proc; return self; }

/* Replace these! */
- (int) sliderMin { return 0; }
- (int) sliderMax { return 0; }
@end


/*------------------------------------------------------------*/
/* Horizontal Slider.                                         */
/*------------------------------------------------------------*/


@implementation HSlider
- (id) init
{
    [super init];
    handle_pos = 0;
    slider_precision = 10;
    handle_w = handle_h = 10;
    return self;
}

- (id) setX:(int)x_ Y:(int)y_ W:(int)w_ H:(int)h_
{
    [super setX:x_ Y:y_ W:w_ H:h_];
    handle_h = h - 2*v_padding;
    return self;
}

- (int) sliderMin { return handle_w/2 + h_padding; }
- (int) sliderMax { return w - handle_w/2 - h_padding; }

- (void) receiveMessage:(int)msg :(int)data
{
    int old_pos = handle_pos;

    if (msg == MSG_MOUSE_HELD && data == 0) {
	int min = [self sliderMin];
	int handle_x = mouse_x - x - min;

	handle_pos = ([self sliderStepSize]/2 + handle_x) * (slider_precision - 1) / [self sliderLength];
	handle_pos = MID(0, handle_pos, slider_precision-1);
    }
    else if (msg == MSG_MOUSE_WHEEL) {
	handle_pos = MID(0, handle_pos - data, slider_precision-1);
    }
    else
        [super receiveMessage:msg :data];

    if (handle_pos != old_pos) {
	flags |= FLAG_DIRTY;
	if (pushed_proc)
	    (*pushed_proc)(self, MSG_HSLIDER, handle_pos);
	if (parent)
	    [parent receiveMessage:MSG_HSLIDER :handle_pos fromChild:self];
    }
}
@end


/*------------------------------------------------------------*/
/* Vertical Slider.                                           */
/*------------------------------------------------------------*/


@implementation VSlider
- (id) init
{
    [super init];
    handle_pos = 0;
    slider_precision = 10;
    handle_w = handle_h = 10;
    return self;
}

- (id) setX:(int)x_ Y:(int)y_ W:(int)w_ H:(int)h_
{
    [super setX:x_ Y:y_ W:w_ H:h_];
    handle_w = w - 2*h_padding;
    return self;
}

- (int) sliderMin { return handle_h/2 + v_padding; }
- (int) sliderMax { return h - handle_h/2 - v_padding; }

- (void) receiveMessage:(int)msg :(int)data
{
    int old_pos = handle_pos;

    if (msg == MSG_MOUSE_HELD && data == 0) {
	int min = [self sliderMin];
	int handle_y = mouse_y - y - min;

	handle_pos = ([self sliderStepSize]/2 + handle_y) * (slider_precision - 1) / [self sliderLength];
	handle_pos = MID(0, handle_pos, slider_precision-1);
    }
    else if (msg == MSG_MOUSE_WHEEL) {
	handle_pos = MID(0, handle_pos + data, slider_precision-1);
    }
    else
        [super receiveMessage:msg :data];

    if (handle_pos != old_pos) {
	flags |= FLAG_DIRTY;
	if (pushed_proc)
	    (*pushed_proc)(self, MSG_VSLIDER, handle_pos);
	if (parent)
	    [parent receiveMessage:MSG_VSLIDER :handle_pos fromChild:self];
    }
}
@end
