/* $Id: Button.c,v 1.2 1997/06/27 12:41:12 archer Exp $
 *	BUTTON.C - Handle Button objects
 *
 * This is the basic Push Button. More complex buttons can be created by
 * using a basic button, and altering a few action procedures.
 */
#include <Widget/ButtonP.h>
#include <Widget/ShellP.h>
#include <Widget/drawP.h>
#include <Widget/fontsP.h>
#include <X11/keysym.h>


/**
 ** X11_BUTTON_EXPOSE
 **	Redraw a basic button
 **/
void x11__button_expose(X11_widget wdg, XEvent *dummy)
{
unsigned int	t;
/*
 * Setup
 */
	x11__draw_start(wdg);
	t = wdg->shadow_thickness;
	if (t < 2)
		t = 2;
/*
 * Differing style in color-poor environments
 */
	if (x11__is_monochrome) {
/*** HACK ***/
	} else {
/*
 * Focussed?
 */
		if (wdg->focus_thickness)
			x11__draw_lined(wdg->has_focus ? wdg->focus_color
						: wdg->parent->background,
						wdg->focus_thickness);
		x11__shadows_gc();
/*
 * Default item?
 */
		if (wdg->is_default) {
			x11__draw_downshadow(t);
			x11__draw_lined(wdg->active_bk, wdg->margin_inside);
		}
/*
 * Depressed?
 */
		if (wdg->is_selected)
			x11__draw_downshadow(t);
		else
			x11__draw_upshadow(t);
/*
 * Shadow always there
 */
	}
	x11__label_draw_active(W_LABEL);
}


/**
 ** Internal: BUTTON_RELEASE
 **	Mouse was released in the button
 **/
static void button_release(X11_widget wdg, XEvent *mouse)
{
X11_callback	c;
/*
 * Pop the button
 */
	wdg->is_depressed = False;
	if (!wdg->is_selected)
		return;
/*
 * Do the callback
 */
	if (mouse->xbutton.x >= 0 && mouse->xbutton.x < wdg->w &&
	    mouse->xbutton.y >= 0 && mouse->xbutton.y < wdg->h &&
	    !wdg->is_disabled &&
	    (c = W_BUTTON->action) != 0)
			(*c)(wdg, W_BUTTON->userdata);
/*
 * Escape from refresh
 */
	x11__core_release(wdg, mouse);
}


/**
 ** Internal: BUTTON_DEFAULT
 **	Button was activated by default
 **/
static void button_default(X11_widget wdg, XEvent *e)
{
X11_callback	c;
/*
 * If depressed for anything else...
 */
	if (wdg->is_disabled)
		return;
	switch (x11__key_sym) {
	    case XK_Return:
	    case XK_Execute:
	    case XK_KP_Enter:
	    case XK_space:
		break;
	    default:
		return;
	}
/*
 * Emulate push
 */
	x11__core_press(wdg, (XEvent *)0);
	if (!wdg->unmapped)
		(*wdg->on_expose)(wdg, (XEvent *)0);
/*
 * Make sure the user will see the action
 */
	XSync(x11__screen, False);
/*
 * Emulate pop
 */
	wdg->is_depressed = False;
	if ((c = W_BUTTON->action) != 0)
		(*c)(wdg, W_BUTTON->userdata);
	x11__core_release(wdg, (XEvent *)0);
}


/**
 ** X11__BUTTON_GEOMETRY
 **	Compute the geometry of a generic button
 **/
void x11__button_geometry(x11__button *wdg)
{
int	t;
int	w, h;
/*
 * All around the widget
 */
	t  = wdg->label.core.shadow_thickness + wdg->label.core.margin_inside +
	     wdg->label.core.focus_thickness;
	if (wdg->label.core.is_default)
		t += wdg->label.core.shadow_thickness +
		     wdg->label.core.margin_inside;
	t *= 2;
	t += wdg->label.core.border2;
/*
 * Label size
 */
	x11__label_size(&wdg->label);
	w = wdg->label.w + t;
	if (wdg->label.w_str)
		w += 2 * wdg->label.core.margin_inside;
	h = wdg->label.h + t;
	wdg->label.core.w_min   = w;
	wdg->label.core.h_min   = h;
	wdg->label.core.fixed_w = True;
	wdg->label.core.fixed_h = True;
}


/**
 ** Internal: BUTTON_GEOMETRY
 **	Compute the geometry of the button
 **/
static void button_geometry(X11_widget wdg, XEvent *dummy)
{
	x11__button_geometry(W_BUTTON);
	x11__widget_grow(wdg);
}


/**
 ** X11_BUTTON_DEFAULTS
 **	Button becomes a default
 **/
void X11_ButtonDefaults(X11_widget wdg)
{
/*
 * Default is that
 */
	wdg->is_default = True;
	x11__default_gets(wdg);
	if (!wdg->has_focus)
		X11_ShellFocus(wdg);
	if (!wdg->unmapped && wdg->id)
		(*wdg->on_expose)(wdg, (XEvent *)0);
}


/**
 ** X11_BUTTON_SET_CALL
 **	Changes the callback for a button
 **/
void X11_ButtonSetCall(X11_widget wdg, X11_callback call, void *data)
{
	W_BUTTON->action   = call;
	W_BUTTON->userdata = data;
}


/**
 ** X11_BUTTON
 **	Create a Button window
 **/
X11_widget X11_Button(X11_widget parent, char *name, char *text, X11_icon *icon,
						X11_callback c, void *data)
{
x11__button	*object;
char		*f;
/*
 * Get resource
 */
	object = allocator(x11__button);
	x11__core_setup(&object->label.core, parent, "Button", name);
/*
 * Initialize fields
 */
	object->label.core.event_mask        = ExposureMask|
						ButtonPressMask|
						ButtonReleaseMask|
						PointerMotionMask|
						PointerMotionHintMask;
	object->label.core.on_button_press   = x11__core_press;
	object->label.core.on_button_release = button_release;
	object->label.core.on_expose         = x11__button_expose;
	object->label.core.on_key_press      = button_default;
	object->label.core.on_enter_window   = x11__core_enter;
	object->label.core.on_exit_window    = x11__core_exit;
	object->label.core.on_motion_notify  = x11__core_motion;
	object->label.core.on_destruction    = x11__label_cleanup;
	object->label.core.on_geometry_check = button_geometry;
/*
 * Look and feel-dependent
 */
	object->label.core.shadow_thickness = 2;
	object->label.core.margin_inside    = 2;
	object->label.core.focus_thickness  = 2;
	object->label.core.can_active       = True;
	object->label.core.can_focus        = True;
	x11__focus_might(&object->label.core);
	f = x11__font_helvetica12;
/*
 * Special defaults when Icon present
 */
	if (icon) {
		X11_IconUsed(icon);
		object->label.icon       = icon;
		object->label.icon_above = True;
		f = x11__font_helvetica10;
	}
/*
 * Resources
 */
	x11__label_resources(&object->label, f, text);
/*
 * Specials
 */
	object->action    = c;
	object->userdata  = data;
	object->label.core.fixed_w = True;
	object->label.core.fixed_h = True;
	x11__button_geometry(object);
	object->label.core.w = object->label.core.w_min;
	object->label.core.h = object->label.core.h_min;
/*
 * Ok
 */
	return (X11_widget)object;
}
