extern "C" {
#include <string.h>
#include <memory.h>
#ifdef _BSDI
#include <stdlib.h>
#else
#include <malloc.h>
#endif
}
#include "twin.h"

/* ----------------------------------------------------------------------------
 * MenuButton
 */

MenuButton::MenuButton(char *InitName,void (*InitFnc)(MenuButton *v,int ch),
		View *InitParam,
		int InitX, int InitY, int InitB, int InitH)
	: View(InitName,InitX,InitY,InitB,InitH)
{	fnc = InitFnc;
	param = InitParam;
	b=strlen(name);
	h=1;
	}

void MenuButton::expose(int ExX,int ExY,int ExB,int ExH)
{	char *t;
	char t1[2];

	if (!visible) return;

        if (!ExB || (ExB+ExX > b)) ExB = b-ExX;
        if (!ExH || (ExH+ExY > h)) ExH = h-ExY;

	t=strdup(name+ExX);
	if ((int)strlen(t) > ExB) t[ExB] = 0;

	if (ExX==0) {
		t1[0]=*t;
		t1[1]=0;
		tw_term_puts(RealX(ExX),RealY(ExY), TW_BOLD,t1);
		if (ExB>1)
			tw_term_puts(RealX(ExX+1),RealY(ExY), TW_NORMAL,t+1);
		}
	else	tw_term_puts(RealX(ExX),RealY(ExY), TW_NORMAL,t);

	free(t);
	}

void MenuButton::event(int EvX,int EvY,int EvKey)
{	if ((EvKey == TERM_MAUS1) || (EvKey == TERM_CR)) {
		if (fnc != SubMenu) {
			parent->focus_out(EvKey);
			VRoot.focus=&VRoot;
			if (!param) VRoot.set_cursor(0,0);
			else
			if (!param->visible) VRoot.set_cursor(0,0);
			else param->focus_in(0);
			}
		if (fnc) (*fnc)(this,TERM_CR);
		}
	}

/* ----------------------------------------------------------------------------
 * ViewMenu
 */

ViewMenu::ViewMenu(char *InitName, ViewMenu *ParMenu, MenuLoad *load)
	: ViewContainer(InitName, 0, 0, 0, 0)
{	MenuLoad *l;
	MenuButton *v;
	int vx,vy;

	par_menu = ParMenu;

	x = 0; y = 0;

	if (par_menu) {
		vx=1; vy=1;
		b = 3; h=2;
		}
	else {	vx=0; vy=0;
		b = max_x; h=2;
		}

	if (par_menu) {
		l = load; while (l) {
                	if (l->name) {
				if (b < (int)strlen(l->name)+2) b=strlen(l->name)+2;
				l++;
				}
			else	l=0;
			}
		}

	l = load; while (l) {
		if (l->name) {
			v = new MenuButton(l->name,l->fnc,l->param,
					vx,vy,0,0);
			v->transaction=l->trans;
			add(v);
			v->map(this);

			if (par_menu) {
				vy++;
				v->b = b-2;
				}
			else {	vx+=strlen(v->name)+1;

				if (l->param && !l->param->x && !l->param->y) {
					l->param->x = RealX(vx);
					l->param->y = 1;
					}
				}
			l++;
			}
		else	l=0;
		}
	if (par_menu) h=vy+1;
	}

void ViewMenu::expose(int ExX,int ExY,int ExB,int ExH)
{	int i;
        char *line;
	int rx,ry;

        if (!visible) return;

        rx = RealX(0);
        ry = RealY(0);

        if (!ExB || (ExB+ExX > b)) ExB = b-ExX;
        if (!ExH || (ExH+ExY > h)) ExH = h-ExY;

	line = (char*)setmalloc(b+1);

	if (par_menu) for (i=0; i<h; i++) {
                if ((i == 0) || (i == h-1)) {
                        memset(line,'q'+0x20,b); line[b]=0;
			if (i == 0) {
				line[0] = 'l'+0x20;
				line[b-1] = 'k'+0x20;
				}
			else {	line[0] = 'm'+0x20;
				line[b-1] = 'j'+0x20;
				}
                        }
                else {  memset(line,' ',b); line[b]=0;
                        line[0] = 'x'+0x20; line[b-1] = 'x'+0x20;
			}
                if ((i >= ExY) && (i < ExY+ExH)) {
                        line[ExX+ExB] = 0;
                        tw_term_puts(rx+ExX,ry+i,TW_NORMAL,line+ExX);
                        }
                if (i >= ExY+ExH) break;
                }
	else
	if (ExY+ExH == 2) {
		memset(line,'q'+0x20,b); line[b]=0;
		line[ExX+ExB] = 0;
		tw_term_puts(rx+ExX,ry+1,TW_NORMAL,line+ExX);
                }
        free(line);

        sub_expose(ExX,ExY,ExB,ExH);
        }

void ViewMenu::event(int EvX,int EvY,int EvKey)
{       struct View *tmp;
	struct ViewList *v;

	if (VRoot.focus != this) {
                if (VRoot.focus != par_menu) VRoot.focus->focus_out(EvKey);
                VRoot.focus = this;
                }

	if (!par_menu && (EvKey==TERM_DN)) EvKey=TERM_CR;

	switch(EvKey) {
	case TERM_ESC :
		focus_out(EvKey);
		VRoot.set_cursor(RealX(0),0);
		break;
	case TERM_UP :
		if (par_menu) {
			if (EvY>1) set_cursor(1,EvY-1);
			else {	set_cursor(0,-1);
				unmap();
				}
			}
		break;
	case TERM_DN :
		if (par_menu && (EvY+2<h)) set_cursor(1,EvY+1);
		break;
	case TERM_LE :
		if (!par_menu) {
			v = viewlist; tmp =0;
			while (v) {
				if (v->next && v->next->view &&
				    (v->next->view->x == EvX)) {
					tmp=v->view;
					v = 0;
					}
				else	v=v->next;
				}
			if (tmp) tmp->set_cursor(0,0);
			}
		else {	set_cursor(0,-1);
			unmap();
			par_menu->event(stdterm->x,0,EvKey);
			par_menu->event(stdterm->x,0,TERM_CR);
			}
		break;
	case TERM_RE :
		if (!par_menu) {
			v = viewlist; tmp =0;
			while (v) {
				if (v->next && v->next->view &&
				    (v->view->x == EvX)) {
					tmp=v->next->view;
					v = 0;
					}
				else	v=v->next;
				}
			if (tmp) tmp->set_cursor(0,0);
			}
		else {	set_cursor(0,-1);
			unmap();
			par_menu->event(stdterm->x,0,EvKey);
			par_menu->event(stdterm->x,0,TERM_CR);
			}
		break;
	case TERM_CR :
	case TERM_MAUS1 :
	case TERM_MAUS2 :
	case TERM_MAUS3 :
		if (par_menu) EvX=1;

		if (tmp=find(EvX,EvY))
			tmp->event(EvX-tmp->x, EvY-tmp->y,EvKey);
		break;
	default :
		if ((EvKey>='a') && (EvKey<='z')) EvKey -= 32;
		if ((EvKey>='A') && (EvKey<='Y')) {
			v = viewlist; tmp =0;
			while (v) {
				if (*(v->view->name) == EvKey) {
					tmp=v->view;
					v = 0;
					}
				else	v=v->next;
				}
			if (tmp) tmp->event(EvX-tmp->x, EvY-tmp->y,TERM_CR);
			}
		}
	}
		
void ViewMenu::resize(int SizB,int SizH)
{       int vis;
        View *par;

	if (!par_menu) {
		vis = visible; par = parent;
		if (vis) unmap();
		b=max_x;
		if (vis) map(par);
		}
	}
		
void ViewMenu::focus_out(int reason)
{	if (par_menu) {
		unmap();
		par_menu->focus_out(reason);
		}
	}
