/* $Id: Menuitem.c,v 1.5 1997/05/01 15:22:10 archer Exp $
 *	MENUITEM.C - Handle MenuItem objects
 *
 * MenuItem are always children of Menu or MenuBar, which has some specific
 * constraints.
 */
#include <Widget/MenuItemP.h>
#include <Widget/MenuP.h>
#include <Widget/Shell.h>
#include <Widget/IconP.h>
#include <Widget/drawP.h>
#include <Widget/fontsP.h>
#include <Widget/MenuBarP.h>
#include <Widget/MenuButtonP.h>
#include <Widget/ArrowP.h>
#include <ctype.h>


/**
 ** External variables
 **/
char	x11__menuitem_class[] = "MenuItem";
#define MENUITEM_ARROW_SIZE	8


/**
 ** Private variables
 **/
static GC	item_gc;
#if 0
#include "pixmap/tick.xbm"
static X11_icon	tick_icon = X11_IconMono(tick_width, tick_height, tick_bits);
#endif


/**
 ** Internal:GENERIC_EXPOSE
 **	Redraw the item insides
 **/
static void generic_expose(x11__menuitem *wdg)
{
unsigned long	bk, fg;
GC		gc;
boolean		disabled;
/*
 * Keep track of "real" foreground, then use active
 */
	if (wdg->menub.button.label.core.is_disabled) {
		disabled = True;
		gc = x11__stippled_gc;
	} else {
		disabled = False;
		gc = item_gc;
	}
	if (wdg->menub.button.label.core.is_active) {
		bk = wdg->menub.button.label.core.active_bk;
		fg = wdg->menub.button.label.core.active_fg;
	} else {
		bk = wdg->menub.button.label.core.background;
		fg = wdg->menub.button.label.core.foreground;
	}
	XSetForeground(x11__screen, gc, fg);
/*
 * Draw checkbox?
 */
	x11__draw_fit_h(wdg->menub.button.label.h);
	if (wdg->checkbox && wdg->checked) {
		x11__draw_push();
		x11__x_left += wdg->menub.button.label.core.margin_inside;
		x11__x_w = wdg->checkbox_size;
		x11__draw_fit_h(x11__x_w);
		x11__x_right = x11__x_left + x11__x_w - 1;
		x11__draw_downshadow(wdg->menub.button.label.core.shadow_thickness);
		x11__draw_filled(wdg->menub.button.label.core.active_bk);
		x11__draw_pop();
	}
/*
 * Draw underline?
 */
	x11__x_left = wdg->menub.left_margin;
	if (wdg->underline_ends)
		XDrawLine(x11__screen, x11__cur_id, gc,
				x11__x_left + wdg->underline_start, x11__y_bot,
				x11__x_left + wdg->underline_ends , x11__y_bot);
/*
 * Draw text of menu
 */
	x11__x_w = 0;
	x11__label_draw_active(&wdg->menub.button.label);
}


/**
 ** Internal: ITEM_EXPOSE
 **	MenuItem gets a shadow, focus, and color reversion when active
 **/
static void item_expose(X11_widget wdg, XEvent *dummy)
{
/*
 * Draw a shadow around?
 */
	x11__draw_start(wdg);
	x11__shadows_gc();
	if (wdg->is_active)
		x11__draw_upshadow(wdg->shadow_thickness);
	else
		x11__draw_nothing(wdg->shadow_thickness);
/*
 * Draw the arrow
 */
	if (wdg->child && strcmp(wdg->parent->class, x11__menu_class) == 0) {
		x11__draw_push();
		x11__x_right -= wdg->margin_inside;
		x11__draw_fit_h(MENUITEM_ARROW_SIZE);
		x11__x_left   = x11__x_right - (MENUITEM_ARROW_SIZE-1);
		x11__x_w      = MENUITEM_ARROW_SIZE;
		XSetForeground(x11__screen, x11__back_gc, wdg->active_bk);
		x11__draw_arrow(X11_ARROW_RIGHT, x11__back_gc,
					x11__topleft_gc, x11__bottomright_gc);
		x11__draw_pop();
	}
/*
 * Draw the text & icon parts
 */
	generic_expose(W_MENUITEM);
}


/**
 ** Internal: ITEM_ENTER
 **	The cursor enter an item (while menu was active is implied...)
 **/
static void item_enter(X11_widget wdg, XEvent *dummy)
{
X11_widget	c;
/*
 * Change look of Item
 */
	if (wdg->is_disabled)
		return;
	x11__core_press(wdg, dummy);
/*
 * Which menu is there?
 */
	c = wdg->child;
	if (!c || strcmp(c->class, x11__menu_class))
		return;
/*
 * Pop sub-menu
 */
	x11__menu_pop(c);
}


/** 
 ** Internal: ITEM_RELEASE
 **	The button was released while inside this item
 **	(while menu was active is implied...)
 **/
static void item_release(X11_widget wdg, XEvent *dummy)
{
/*
 * Call the callback
 */
	if (!wdg->is_disabled) {
		if (W_MENUITEM->callback)
			(*W_MENUITEM->callback)(wdg, W_BUTTON->userdata,
							x11__menu_index(wdg));
		else
			if (W_BUTTON->action)
				(*W_BUTTON->action)(wdg, W_BUTTON->userdata);
	}
/*
 * No longer inside
 */
	x11__core_release(wdg, dummy);
}


/**
 ** Internal: ITEM_PRESS
 **	The button was depressed while inside this menu item. This assumes
 **	we're not in MenuMode (else, the event would be unreported)
 **/
static void item_press(X11_widget wdg, XEvent *e)
{
	if (!wdg->is_disabled)
		x11__menu_open(wdg->parent, e);
}


/**
 ** Internal: GEOMETRY
 **	The menu item has a simple geometry
 **/
static void item_geometry(X11_widget wdg, XEvent *dummy)
{
int	m;
/*
 * Basic item geometry
 */
	x11__menub_geometry(W_MENUBUTTON);
/*
 * Include sub-menu arrow?
 */
	if (wdg->child && strcmp(wdg->parent->class, x11__menu_class) == 0) {
		m = wdg->margin_inside + MENUITEM_ARROW_SIZE;
		W_MENUBUTTON->right_margin += m;
		wdg->w_min += m;
		m += wdg->margin_inside + wdg->border2 + 2 * wdg->shadow_thickness;
		if (m > wdg->h_min)
			wdg->h_min = m;
	}
/*
 * Include check mark?
 */
	if (W_MENUITEM->checkbox) {
		m = wdg->shadow_thickness;
		if (m < 3)
			m = 3;
		m += wdg->shadow_thickness * 2;
		W_MENUITEM->checkbox_size = m;
		m += wdg->margin_inside;
		W_MENUBUTTON->left_margin += m;
		wdg->w_min += m;
	}
}


/**
 ** Internal: X11_MENU_INDEX
 **	Returns the position of the MenuItem within its container
 **/
long x11__menu_index(X11_widget wdg)
{
X11_widget	menu;
long		count = 0;
/*
 * Loop
 */
	for (menu = wdg->parent->child; menu; menu = menu->sibling)
		if (menu == wdg)
			return count;
		else
			if (strcmp(menu->class, x11__menuitem_class) == 0)
				count++;
	return -1;
}


/**
 ** X11_MENU_ITEM_CHECK
 **	Sets/Resets the checkmark on a menu item
 **/
void X11_MenuItemCheck(X11_widget wdg, boolean mark)
{
	W_MENUITEM->checkbox = True;
	W_MENUITEM->checked  = mark;
}


/**
 ** X11_MENUITEM
 **	Create a MenuItem window
 **/
X11_widget X11_MenuItem(X11_widget parent, char *name, char *text, char key,
						X11_callback act, void *data)
{
x11__menuitem	*object;
XFontStruct	*info;
int		i;
/*
 * Get resource
 */
	object = allocator(x11__menuitem);
	x11__core_setup(&object->menub.button.label.core, parent, x11__menuitem_class, name);
/*
 * Initialize fields
 */
	object->menub.button.label.core.event_mask        = ButtonPressMask|ButtonReleaseMask|
					ExposureMask|PointerMotionMask;
	object->menub.button.label.core.on_button_press   = item_press;
	object->menub.button.label.core.on_button_release = item_release;
	object->menub.button.label.core.on_destruction    = x11__label_cleanup;
	object->menub.button.label.core.on_enter_window   = item_enter;
	object->menub.button.label.core.on_exit_window    = x11__core_release;
	object->menub.button.label.core.on_expose         = item_expose;
	object->menub.button.label.core.on_geometry_check = item_geometry;
/*
 * Get values
 */
	object->menub.button.label.core.margin_inside       = 2;
	object->menub.button.label.core.shadow_thickness    = 2;
	object->menub.button.action   = act;
	object->menub.button.userdata = data;
	object->menub.side_margin     = 2;
/*
 * Font
 */
	x11__menub_resources(&object->menub, x11__font_helveticabold12, text);
/*
 * Recompute size
 */
	x11__label_size(&object->menub.button.label);
	object->menub.button.label.core.fixed_w    = True;
	object->menub.button.label.core.fixed_h    = True;
	object->menub.button.label.core.can_active = True;
/*
 * Figure key location
 */
	object->key = key;
	if (key) {
		for (i = 0; i < text[i]; i++)
			if (text[i] == key)
				break;
		if (text[i]) {
			info = object->menub.button.label.font;
			object->underline_start = XTextWidth(info, text, i);
			object->underline_ends  = XTextWidth(info, text, i+1)-1;
		}
	}
/*
 * Allocate GC
 */
	if (!item_gc)
		item_gc = x11__widget_gc(&object->menub.button.label.core);
/*
 * Ok
 */
	return OBJECT_P;
}


/**
 ** X11_SUB_MENU
 **	Wrapper that creates a menu item, then attaches a sub-menu to it
 **/
X11_widget X11_SubMenuItem(X11_widget parent, char *name, char *title, char key)
{
X11_widget	item;
/*
 * Create item
 */
	item = X11_MenuItem(parent, name, title, key, 0, 0);
/*
 * Return Menu
 */
	return X11_Menu(item, 0);
}
