#include "MGMenu.h"


MGMenuEntry::MGMenuEntry(TGMenuEntry *ent)
{
    memcpy(this, ent, sizeof(*ent));
}

// -------------------------------------------------------------
//
// Return the keycode corresponding to the hot string of
// a TGmenuEntry
//
UInt_t MGPopupMenu::GetKeyCode(TGMenuEntry *el)
{
    TGHotString *str = MGMenuEntry(el).GetLabel();
    return gVirtualX->KeysymToKeycode(str->GetHotChar());
}

// -------------------------------------------------------------
//
// Bind all hot keys used in this popup menu subsequentlt
// to the TGMainFrame and send a HandleKey message to the
// TGWindow
//
void MGPopupMenu::BindKeys(const TGWindow *w, TGMainFrame *frame)
{
    TIter Next(fEntryList);
    TGMenuEntry *el;

    //
    // Loop Through all entries
    //
    while ((el=(TGMenuEntry*)Next()))
    {
        switch (el->GetType())
        {
            //
            // For seperators and labels nothing to do
            //
        case kMenuSeparator:
        case kMenuLabel:
            continue;

            //
            // For an entry and a popup menu bind the hot key
            // In case of a popup menu call BindKeys subsequently
            //
        case kMenuEntry:
        case kMenuPopup:
            frame->BindKey(w, GetKeyCode(el), kKeyMod1Mask);
            if (el->GetType()==kMenuPopup)
                MGMenuEntry(el).GetPopup()->BindKeys(w, frame);
            continue;
        }
    }
}

/*
 kMenuActiveMask  = BIT(0),
 kMenuEnableMask  = BIT(1),
 kMenuDefaultMask = BIT(2),
 kMenuCheckedMask = BIT(3),
 kMenuRadioMask   = BIT(4),
 kMenuHideMask    = BIT(5)
 */

// -------------------------------------------------------------
//
//  Handle a keyboard event. Return kFALSE in case of a
//  successfully send message, which means: close all open
//  popups.
//
Bool_t MGPopupMenu::HandleKey(Event_t *evt)
{
    //
    // Loop through all entries in this popup menu. If the entry is
    // an open popup menu send the key event to the open popup.
    //
    TIter Next(fEntryList);
    TGMenuEntry *el;
    while ((el=(TGMenuEntry*)Next()))
    {
        if (el->GetType()==kMenuPopup && el->GetStatus()&kMenuActiveMask)
            return MGMenuEntry(el).GetPopup()->HandleKey(evt);
    }

    Next.Reset();

    //
    // If no open popup is found search the pressed key in this
    // popup menu.
    //
    while ((el=(TGMenuEntry*)Next()))
    {
        switch (el->GetType())
        {
            //
            // Do nothing
            //
        case kMenuSeparator:
        case kMenuLabel:
            continue;

            //
            // If the keycode corresponds to the hot key
            // of this entry and the entry is enabled activate the entry
            // and send the corresponding message/
            //
        case kMenuEntry:
            if (GetKeyCode(el)==evt->fCode && el->GetStatus()&kMenuEnableMask)
            {
                Activate(el);
                SendMessage(fMsgWindow, MK_MSG(kC_COMMAND, kCM_MENU),
                            el->GetEntryId(), (Long_t)MGMenuEntry(el).GetUserData());
                return kFALSE;
            }
            continue;

            //
            // If the keycode corresponds to the hot key
            // of this popup menu activate the popup menu.
            //
        case kMenuPopup:
            if (GetKeyCode(el)!=evt->fCode)
                continue;

            Activate(el);
            HandleTimer(NULL);
            return kTRUE;
        }
    }
    return kTRUE;
}

// -------------------------------------------------------------
//
// Bind the keys of all popups subsequently to the given main
// frame. The menu bar hot keys are already bound by TGMenuBar.
// Bind the Escape key to close the popups, too.
//
void MGMenuBar::BindKeys(TGMainFrame *frame)
{
    TGFrameElement *el=NULL;
    TIter Next(fList);
    while ((el = (TGFrameElement *)Next()))
        ((MGPopupMenu*)((TGMenuTitle *) el->fFrame)->GetMenu())->BindKeys(this, frame);

    frame->BindKey(this, 9/*ESC*/, 0);
}

// -------------------------------------------------------------
//
// Handle the keyboard event send to this menu bar.
//
Bool_t MGMenuBar::HandleKey(Event_t *event)
{
    //
    // If this isn't a pressed key do nothing
    //
    if (event->fType != kGKeyPress)
        return kTRUE;

    //
    // Check whether one popup is alreadu open
    //
    TGFrameElement *el=NULL;
    TIter Next(fList);
    while ((el = (TGFrameElement *)Next()))
    {
        if (!((TGMenuTitle*)el->fFrame)->GetState())
            continue;

        TGMenuTitle &f = *(TGMenuTitle*)el->fFrame;

        //
        // If a open popup is found redirect the key event to this
        // popup menu
        //
        Bool_t rc = ((MGPopupMenu*)f.GetMenu())->HandleKey(event);

        //
        // If a message could be successfully send or the escape key
        // was pressed close the popup.
        //
        if (!rc || event->fCode==9/*ESC*/)
        {
            f.SetState(kFALSE);
            gVirtualX->GrabPointer(0, 0, 0, 0, kFALSE);  // ungrab pointer
            fCurrent = 0;
        }

        return kTRUE;
    }

    return TGMenuBar::HandleKey(event);
}
