/* ---------------- menubar.c ------------------ */

#include "dflat32/dflat.h"

static void reset_menubar(DFWINDOW);

static struct {
    int x1, x2;     /* position in menu bar */
    char sc;        /* shortcut key value   */
} menu[10];
static int mctr;

MBAR *ActiveMenuBar;
static MENU *ActiveMenu;

static DFWINDOW mwnd;
static BOOL Selecting;

static DFWINDOW Cascaders[MAXCASCADES];
static int casc;
static DFWINDOW GetDocFocus(void);

/* ----------- SETFOCUS Message ----------- */
static int SetFocusMsg(DFWINDOW wnd, PARAM p1)
{
	int rtn;
	rtn = BaseWndProc(MENUBAR, wnd, SETFOCUS, p1, 0);
	if (!(int)p1)
		DfSendMessage(GetParent(wnd), ADDSTATUS, 0, 0);
	return rtn;
}

/* --------- BUILDMENU Message --------- */
static void BuildMenuMsg(DFWINDOW wnd, PARAM p1)
{
    int offset = 3;
    reset_menubar(wnd);
    mctr = 0;
    ActiveMenuBar = (MBAR *) p1;
    ActiveMenu = ActiveMenuBar->PullDown;
    while (ActiveMenu->Title != NULL &&
            ActiveMenu->Title != (void*)-1)
    {
        char *cp;
        if (strlen(GetText(wnd)+offset) <
                strlen(ActiveMenu->Title)+3)
            break;
        GetText(wnd) = DFrealloc(GetText(wnd),
            strlen(GetText(wnd))+5);
        memmove(GetText(wnd) + offset+4, GetText(wnd) + offset,
                strlen(GetText(wnd))-offset+1);
        CopyCommand(GetText(wnd)+offset,ActiveMenu->Title,FALSE,
                wnd->WindowColors [STD_COLOR] [BG]);
        menu[mctr].x1 = offset;
        offset += strlen(ActiveMenu->Title) + (3+MSPACE);
        menu[mctr].x2 = offset-MSPACE;
        cp = strchr(ActiveMenu->Title, SHORTCUTCHAR);
        if (cp)
            menu[mctr].sc = tolower(*(cp+1));
        mctr++;
        ActiveMenu++;
    }
    ActiveMenu = ActiveMenuBar->PullDown;
}

/* ---------- PAINT Message ---------- */
static void PaintMsg(DFWINDOW wnd)
{
	if (Selecting)
		return;
    if (wnd == inFocus)
        DfSendMessage(GetParent(wnd), ADDSTATUS, 0, 0);
    SetStandardColor(wnd);
    wputs(wnd, GetText(wnd), 0, 0);
    if (ActiveMenuBar == NULL)
	return;
    if (ActiveMenuBar->ActiveSelection != -1 &&
            (wnd == inFocus || mwnd != NULL))    {
        char *sel, *cp;
        int offset, offset1;

        sel = DFmalloc(200);
        offset=menu[ActiveMenuBar->ActiveSelection].x1;
        offset1=menu[ActiveMenuBar->ActiveSelection].x2;
        GetText(wnd)[offset1] = '\0';
        SetReverseColor(wnd);
        memset(sel, '\0', 200);
        strcpy(sel, GetText(wnd)+offset);
        cp = strchr(sel, CHANGECOLOR);
        if (cp != NULL)
            *(cp + 2) = background | 0x80;
        wputs(wnd, sel,
            offset-ActiveMenuBar->ActiveSelection*4, 0);
        GetText(wnd)[offset1] = ' ';
        if (mwnd == NULL && wnd == inFocus) {
            char *st = ActiveMenu
                [ActiveMenuBar->ActiveSelection].StatusText;
            if (st != NULL)
                DfSendMessage(GetParent(wnd), ADDSTATUS,
                    (PARAM)st, 0);
        }
        free(sel);
    }
}

/* ------------ KEYBOARD Message ------------- */
static void KeyboardMsg(DFWINDOW wnd, PARAM p1)
{
	MENU *mnu;
	int sel;
    if (mwnd == NULL)
    {
        /* ----- search for menu bar shortcut keys ---- */
        int c = tolower((int)p1);
        int a = AltConvert((int)p1);
        int j;
        for (j = 0; j < mctr; j++)    {
            if ((inFocus == wnd && menu[j].sc == c) ||
                    (a && menu[j].sc == a))    {
				DfSendMessage(wnd, SETFOCUS, TRUE, 0);
                DfSendMessage(wnd, MB_SELECTION, j, 0);
                return;
            }
        }
    }
    /* -------- search for accelerator keys -------- */
    mnu = ActiveMenu;
    while (mnu->Title != (void *)-1)    {
        struct PopDown *pd = mnu->Selections;
        if (mnu->PrepMenu)
            (*(mnu->PrepMenu))(GetDocFocus(), mnu);
        while (pd->SelectionTitle != NULL)    {
            if (pd->Accelerator == (int) p1)    {
                if (pd->Attrib & INACTIVE)
                    beep();
                else    {
                    if (pd->Attrib & TOGGLE)
                        pd->Attrib ^= CHECKED;
                    DfSendMessage(GetDocFocus(),
                        SETFOCUS, TRUE, 0);
                    DfPostMessage(GetParent(wnd),
                        DFM_COMMAND, pd->ActionId, 0);
                }
                return;
            }
            pd++;
        }
        mnu++;
    }
	switch ((int)p1)
	{
		case F1:
			if (ActiveMenu == NULL || ActiveMenuBar == NULL)
				break;
			sel = ActiveMenuBar->ActiveSelection;
			if (sel == -1)
			{
				BaseWndProc(MENUBAR, wnd, KEYBOARD, F1, 0);
				return;
			}
			mnu = ActiveMenu+sel;
			if (mwnd == NULL ||
				mnu->Selections[0].SelectionTitle == NULL)
			{
				DisplayHelp(wnd,mnu->Title+1);
				return;
			}
			break;

        case '\r':
            if (mwnd == NULL &&
                    ActiveMenuBar->ActiveSelection != -1)
                DfSendMessage(wnd, MB_SELECTION,
                    ActiveMenuBar->ActiveSelection, 0);
            break;
        case F10:
            if (wnd != inFocus && mwnd == NULL)    {
                DfSendMessage(wnd, SETFOCUS, TRUE, 0);
			    if ( ActiveMenuBar->ActiveSelection == -1)
			        ActiveMenuBar->ActiveSelection = 0;
			    DfSendMessage(wnd, PAINT, 0, 0);
                break;
            }
            /* ------- fall through ------- */
        case ESC:
            if (inFocus == wnd && mwnd == NULL)    {
                ActiveMenuBar->ActiveSelection = -1;
                DfSendMessage(GetDocFocus(),SETFOCUS,TRUE,0);
                DfSendMessage(wnd, PAINT, 0, 0);
            }
            break;
        case FWD:
            ActiveMenuBar->ActiveSelection++;
            if (ActiveMenuBar->ActiveSelection == mctr)
                ActiveMenuBar->ActiveSelection = 0;
            if (mwnd != NULL)
                DfSendMessage(wnd, MB_SELECTION,
                    ActiveMenuBar->ActiveSelection, 0);
            else 
                DfSendMessage(wnd, PAINT, 0, 0);
            break;
        case BS:
            if (ActiveMenuBar->ActiveSelection == 0 ||
					ActiveMenuBar->ActiveSelection == -1)
                ActiveMenuBar->ActiveSelection = mctr;
            --ActiveMenuBar->ActiveSelection;
            if (mwnd != NULL)
                DfSendMessage(wnd, MB_SELECTION,
                    ActiveMenuBar->ActiveSelection, 0);
            else 
                DfSendMessage(wnd, PAINT, 0, 0);
            break;
        default:
            break;
    }
}

/* --------------- LEFT_BUTTON Message ---------- */
static void LeftButtonMsg(DFWINDOW wnd, PARAM p1)
{
    int i;
    int mx = (int) p1 - GetLeft(wnd);
    /* --- compute the selection that the left button hit --- */
    for (i = 0; i < mctr; i++)
        if (mx >= menu[i].x1-4*i &&
                mx <= menu[i].x2-4*i-5)
            break;
    if (i < mctr)
        if (i != ActiveMenuBar->ActiveSelection || mwnd == NULL)
            DfSendMessage(wnd, MB_SELECTION, i, 0);
}

/* -------------- MB_SELECTION Message -------------- */
static void SelectionMsg(DFWINDOW wnd, PARAM p1, PARAM p2)
{
    int wd, mx, my;
    MENU *mnu;

	if (!p2)
	{
		ActiveMenuBar->ActiveSelection = -1;
		DfSendMessage(wnd, PAINT, 0, 0);
	}
    Selecting = TRUE;
    mnu = ActiveMenu+(int)p1;
    if (mnu->PrepMenu != NULL)
        (*(mnu->PrepMenu))(GetDocFocus(), mnu);
    wd = MenuWidth(mnu->Selections);
    if (p2)
    {
		int brd = GetRight(wnd);
        mx = GetLeft(mwnd) + WindowWidth(mwnd) - 1;
		if (mx + wd > brd)
			mx = brd - wd;
        my = GetTop(mwnd) + mwnd->selection;
    }
    else
    {
        int offset = menu[(int)p1].x1 - 4 * (int)p1;
        if (mwnd != NULL)
            DfSendMessage(mwnd, CLOSE_WINDOW, 0, 0);
        ActiveMenuBar->ActiveSelection = (int) p1;
        if (offset > WindowWidth(wnd)-wd)
            offset = WindowWidth(wnd)-wd;
        mx = GetLeft(wnd)+offset;
        my = GetTop(wnd)+1;
    }
    mwnd = DfCreateWindow(POPDOWNMENU, NULL,
                mx, my,
                MenuHeight(mnu->Selections),
                wd,
                NULL,
                wnd,
                NULL,
                SHADOW);
	if (!p2)
	{
		Selecting = FALSE;
		DfSendMessage(wnd, PAINT, 0, 0);
		Selecting = TRUE;
	}
	if (mnu->Selections[0].SelectionTitle != NULL)
	{
		DfSendMessage(mwnd, BUILD_SELECTIONS, (PARAM) mnu, 0);
		DfSendMessage(mwnd, SETFOCUS, TRUE, 0);
		DfSendMessage(mwnd, SHOW_WINDOW, 0, 0);
	}
	Selecting = FALSE;
}

/* --------- COMMAND Message ---------- */
static void CommandMsg(DFWINDOW wnd, PARAM p1, PARAM p2)
{
	if (p1 == ID_HELP)
	{
		BaseWndProc(MENUBAR, wnd, DFM_COMMAND, p1, p2);
		return;
	}

	if (isCascadedCommand(ActiveMenuBar, (int)p1))
	{
        /* find the cascaded menu based on command id in p1 */
        MENU *mnu = ActiveMenu+mctr;
        while (mnu->Title != (void *)-1)    {
            if (mnu->CascadeId == (int) p1)    {
                if (casc < MAXCASCADES)    {
                    Cascaders[casc++] = mwnd;
                    DfSendMessage(wnd, MB_SELECTION,
                        (PARAM)(mnu-ActiveMenu), TRUE);
                }
                break;
            }
            mnu++;
        }
    }
    else     {
        if (mwnd != NULL)
            DfSendMessage(mwnd, CLOSE_WINDOW, 0, 0);
        DfSendMessage(GetDocFocus(), SETFOCUS, TRUE, 0);
        DfPostMessage(GetParent(wnd), DFM_COMMAND, p1, p2);
    }
}

/* --------------- CLOSE_POPDOWN Message --------------- */
static void ClosePopdownMsg(DFWINDOW wnd)
{
	if (casc > 0)
		DfSendMessage(Cascaders[--casc], CLOSE_WINDOW, 0, 0);
	else
	{
		mwnd = NULL;
		ActiveMenuBar->ActiveSelection = -1;
		if (!Selecting)
		{
			DfSendMessage(GetDocFocus(), SETFOCUS, TRUE, 0);
			DfSendMessage(wnd, PAINT, 0, 0);
		}
	}
}

/* ---------------- CLOSE_WINDOW Message --------------- */
static void CloseWindowMsg(DFWINDOW wnd)
{
	if (GetText(wnd) != NULL)
	{
		free(GetText(wnd));
		GetText(wnd) = NULL;
	}
	mctr = 0;
	ActiveMenuBar->ActiveSelection = -1;
	ActiveMenu = NULL;
	ActiveMenuBar = NULL;
}

/* --- Window processing module for MENUBAR window class --- */
int MenuBarProc(DFWINDOW wnd, DFMESSAGE msg, PARAM p1, PARAM p2)
{
    int rtn;

    switch (msg)    {
        case CREATE_WINDOW:
            reset_menubar(wnd);
            break;
        case SETFOCUS:
			return SetFocusMsg(wnd, p1);
        case BUILDMENU:
            BuildMenuMsg(wnd, p1);
            break;
        case PAINT:
            if (!isVisible(wnd) || GetText(wnd) == NULL)
                break;
            PaintMsg(wnd);
            return FALSE;
        case BORDER:
		    if (mwnd == NULL)
				DfSendMessage(wnd, PAINT, 0, 0);
            return TRUE;
        case KEYBOARD:
            KeyboardMsg(wnd, p1);
            return TRUE;
        case LEFT_BUTTON:
            LeftButtonMsg(wnd, p1);
            return TRUE;
        case MB_SELECTION:
            SelectionMsg(wnd, p1, p2);
            break;
        case DFM_COMMAND:
            CommandMsg(wnd, p1, p2);
            return TRUE;
        case INSIDE_WINDOW:
            return InsideRect(p1, p2, WindowRect(wnd));
        case CLOSE_POPDOWN:
            ClosePopdownMsg(wnd);
            return TRUE;
        case CLOSE_WINDOW:
            CloseWindowMsg(wnd);
            rtn = BaseWndProc(MENUBAR, wnd, msg, p1, p2);
            return rtn;
        default:
            break;
    }
    return BaseWndProc(MENUBAR, wnd, msg, p1, p2);
}

/* ------------- reset the MENUBAR -------------- */
static void reset_menubar(DFWINDOW wnd)
{
    GetText(wnd) = DFrealloc(GetText(wnd), DfGetScreenWidth()+5);
    memset(GetText(wnd), ' ', DfGetScreenWidth());
    *(GetText(wnd)+WindowWidth(wnd)) = '\0';
}

static DFWINDOW GetDocFocus(void)
{
	DFWINDOW wnd = ApplicationWindow;
	if (wnd != NULL)
	{
		wnd = LastWindow(wnd);
		while (wnd != NULL &&
		       (GetClass(wnd) == MENUBAR ||
		        GetClass(wnd) == STATUSBAR))
			wnd = PrevWindow(wnd);
		if (wnd != NULL)
		{
			while (wnd->childfocus != NULL)
				wnd = wnd->childfocus;
		}
	}
	return wnd ? wnd : ApplicationWindow;
}

/* EOF */
