/*
 * w_menu.c : menu window related routines(NHW_MENU / NHW_TEXT)
 *
 * Copyright (c) Yukihiko Aoki 1999, 2005
 * NetHack may be freely redistributed.  See license for details.
 *
 */

#include "hack.h"

#ifdef NH2K_EXTENDS

#include "win32api.h"
#include "w_main.h"
#include "res/resource.h"

#define BORDERWIDTH     2
#define STRMORE         "(more)"
#define STREND          "(end)"
#define MENU_PREFIX     "? - "

/*
 * structure for menu items
 */
typedef struct tagWINMENUITEM{
    int         glyph;                  /* items glyph         */
    anything    identifier;             /* return value        */
    char        ch;                     /* character           */
    char        gch;                    /* group accelerator   */
    int         attr;                   /* font attribute      */
    char        *str;                   /* item string         */
    BOOL        selected;               /* is item selected?   */
    int         count;                  /* select count        */
    struct tagWINMENUITEM *nmenu;
}WINMENUITEM;

/*
 * menu window property
 */
typedef struct tagWINMENUPROP {
    int max_lines;                      /* maximum line number */
    int glyph_fit_font;
    int glyph_width;
    int glyph_height;
}WINMENUPROP;

/*
 * structure definitions
 */
typedef struct tagWINMENUINFO{
    HBITMAP menubtns;
    BOOL    done;
    HRGN    hrgn;
    int     how;                        /* Menu selection type */
    int     selcount;                   /* Selected count      */
    int     total;                      /* Total items count   */
    BOOL    canceled;                   /* Is canceled?(ESC)   */
    int     visible;                    /* Max items per page  */
    int     curpage;                    /* current page        */
    int     numpage;                    /* page number         */
    WINMENUITEM *menu_first;            /* Item list           */
    FONTINFO    *font;                  /* font                */
    WINMENUPROP *property;              /* property            */
}WINMENUINFO;

/*
 * Local variables
 */
static WINMENUPROP  menu_property;
FONTINFO     menu_font;

/*
 * local functions
 */
static UINT FDECL(MenuWnd_OnNCCalcSize,(HWND,BOOL,NCCALCSIZE_PARAMS *));
static void FDECL(MenuWnd_OnPaint,(HWND));
static void FDECL(MenuWnd_OnNCPaint,(HWND,HRGN));
static void FDECL(MenuWnd_procCalcRect, (WINDESC*, RECT*, RECT*));
static void FDECL(MenuWnd_processKey, (HWND));
static void FDECL(MenuWnd_procDestroy, (WINDESC*));
static void FDECL(MenuWnd_procDisplay, (WINDESC*));
static void FDECL(MenuWnd_procPutStr, (WINDESC*,int,const char*));
static void FDECL(MenuWnd_procDraw, (WINDESC *,HDC));
static void FDECL(MenuWnd_clearElements, (WINDESC*));
static void FDECL(MenuWnd_clearItems, (WINDESC*));
static void FDECL(MenuWnd_saveProperty, (WINMENUPROP *, char *));
static void FDECL(MenuWnd_loadProperty, (WINMENUPROP *, char *));
static void FDECL(MenuWnd_OnLButtonDown, (HWND,BOOL,int,int,UINT));

/***************************************************************************************
 * MenuWnd Window Procedure
 ***************************************************************************************/
LRESULT CALLBACK MenuWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    switch(Msg) {
        HANDLE_MSG(hWnd, WM_NCCREATE,    NHWnd_OnCreate);
        HANDLE_MSG(hWnd, WM_KEYDOWN,     NHWnd_OnKey);
        HANDLE_MSG(hWnd, WM_CHAR,        NHWnd_OnChar);
        HANDLE_MSG(hWnd, WM_SYSKEYDOWN,  NHWnd_OnSysKey);
        HANDLE_MSG(hWnd, WM_NCHITTEST,   NHWnd_OnNCHitTest);
        HANDLE_MSG(hWnd, WM_PAINT,       NHWnd_OnPaint);
        HANDLE_MSG(hWnd, WM_NCCALCSIZE,  MenuWnd_OnNCCalcSize); 
        HANDLE_MSG(hWnd, WM_NCPAINT,     MenuWnd_OnNCPaint);
        HANDLE_MSG(hWnd, WM_LBUTTONDOWN, MenuWnd_OnLButtonDown);
    default:
        return DefWindowProc(hWnd, Msg, wParam, lParam);
    }
}

/*-------------------------------------------------------------------------------------
 *
 *-------------------------------------------------------------------------------------*/
static void MenuWnd_setWindesc(WINDESC *wd, int type, void *pinfo)
{
    wd->exstyle        = WS_EX_PALETTEWINDOW;
    wd->style          = WS_CHILD|WS_CLIPSIBLINGS;
    wd->can_show       = FALSE;
    wd->create_at_init = FALSE;
    wd->draw_memory    = TRUE;
    wd->cname          = "NHMENU";
    wd->wname          = NULL;
    wd->hwnd           = NULL;
    wd->type           = type;
    wd->cur.x          = -1;
    wd->cur.y          = -1;
    wd->more           = FALSE;
    wd->pinfo          = pinfo; 

    wd->procCalcRect   = MenuWnd_procCalcRect;
    wd->procDestroy    = MenuWnd_procDestroy;
    wd->procDisplay    = MenuWnd_procDisplay;
    wd->procClear      = NULL;
    wd->procSetCursor  = NULL;
    wd->procPutStr     = MenuWnd_procPutStr;
    wd->procDraw       = MenuWnd_procDraw;
    wd->next           = NULL;
}

/*-------------------------------------------------------------------------------------
 * WM_NCCALCSIZE
 *-------------------------------------------------------------------------------------*/
static UINT MenuWnd_OnNCCalcSize(HWND hwnd, BOOL fCalcValidRects, NCCALCSIZE_PARAMS *lpcsp)
{
    WINDESC *wd = GETWINDESC(hwnd);
    WINMENUINFO *wmi;
    HDC hdc;

    if(wd) {
        wmi = (WINMENUINFO*)wd->pinfo;
        hdc = GetDC(wd->hwnd);
        lpcsp->rgrc[0].left += (BORDERWIDTH);
        lpcsp->rgrc[0].top +=  (BORDERWIDTH * 2 + Font_height(wmi->font, hdc) + 2);
        lpcsp->rgrc[0].right -= (BORDERWIDTH);
        lpcsp->rgrc[0].bottom -= (BORDERWIDTH * 2 + Font_height(wmi->font, hdc) + 2);
        ReleaseDC(wd->hwnd, hdc);
    }

    return 0;
}

/*--------------------------------------------------------------------------------------
 *
 *-------------------------------------------------------------------------------------*/
static void MenuWnd_procCalcRect(WINDESC *wd, RECT *rcParent, RECT *rcMove)
{
    WINMENUINFO *wmi = (WINMENUINFO *)wd->pinfo;
    int width, height;
    RECT rc;

    GetWindowRect(wd->hwnd, rcMove);
    GetClientRect(g_baseHwnd, &rc);
    width = rcMove->right - rcMove->left;
    height = rcMove->bottom - rcMove->top;

    rcMove->left = 
        ((rc.right - rc.left) - width) / 2;
    rcMove->top = 
        ((rc.bottom - rc.top) - height) / 2;
    rcMove->right = rcMove->left + width;
    rcMove->bottom = rcMove->top + height;
}

/*-------------------------------------------------------------------------------------
 * 
 *-------------------------------------------------------------------------------------*/
static void MenuWnd_calcRect(WINDESC *wd) 
{
    WINMENUINFO *wmi = (WINMENUINFO *)wd->pinfo;
    WINMENUITEM *item;
    int height;
    HDC hdc;
    RECT rc;
    int maxwidth;
    int maxheight;
    int ave;

    hdc = GetDC(wd->hwnd);
    ave = Font_width(wmi->font, hdc);
    height = Font_height(wmi->font, hdc);
    ReleaseDC(wd->hwnd, hdc);

    /*
     * Get number of items can be shown
     */
    wmi->visible = min(wmi->property->max_lines, wmi->total);
    wmi->numpage = wmi->total / wmi->visible + (wmi->total % wmi->visible ? 1 : 0);
    wmi->curpage = 1;

    maxheight = wmi->visible * height;

    maxwidth = 0;
    if(wd->wname) {
        maxwidth = (strlen(wd->wname) + 10) * ave;
    }
    for(item=wmi->menu_first; item!=NULL; item=item->nmenu) {
        int width = 0;

    width = strlen(item->str) * ave;

        if(item->glyph != NO_GLYPH) {
            width += height;
        }
        if(item->ch != 0) {
            width += strlen(MENU_PREFIX) * ave;
        }
        maxwidth = max( width, maxwidth );
    }

    rc.left = 0 ;
    rc.top = 0 ;
    rc.right = maxwidth + BORDERWIDTH*2;
    rc.bottom = maxheight + BORDERWIDTH * 4 + (height + 2) * 2;

    SetWindowPos(wd->hwnd, HWND_TOP, 0, 0,
        (rc.right - rc.left),(rc.bottom - rc.top), SWP_NOMOVE);
    wmi->hrgn = CreateRoundRectRgn(0, 0, rc.right+1, rc.bottom+1, 20, 20);
    SetWindowRgn(wd->hwnd, wmi->hrgn, TRUE);
    NHWnd_moveCenter(wd->hwnd, g_baseHwnd);
}

/*-------------------------------------------------------------------------------------
 * WM_PAINT
 *-------------------------------------------------------------------------------------*/
static void MenuWnd_procDraw(WINDESC *wd, HDC hdc)
{
    WINMENUINFO *mi;
    WINMENUITEM *item;
    COLORREF     textColor, oldBkColor, oldTextColor;
    HBRUSH       selBrs;
    RECT         rcWnd, rcItem, rcTxt, rcGlyph;
    HFONT        oldFont;
    int          glyphOffset;
    char         buf[256];
    int          i;
    int          step;
    POINT        pt;

    mi = (WINMENUINFO*)wd->pinfo;

    step = Font_height(mi->font, hdc);
    step -= 1;

    selBrs = CreateSolidBrush(colormap[CLR_YELLOW]);
    oldBkColor = SetBkColor(hdc,colormap[CLR_BLACK]);
    oldTextColor = SetTextColor(hdc, colormap[CLR_WHITE]);
    oldFont = SelectObject(hdc, mi->font->font_handle);

    GetCursorPos(&pt);
    ScreenToClient(wd->hwnd, &pt);
    GetClientRect(wd->hwnd, &rcWnd);
    FillRect(hdc, &rcWnd, GetStockObject(BLACK_BRUSH));
    CopyRect(&rcItem, &rcWnd);
    rcItem.bottom = rcItem.top + step;
    item = mi->menu_first;

    /* skip */
    for(i=0; i < (mi->curpage-1)*mi->visible; i++,item=item->nmenu);

    while(item && rcItem.top < rcWnd.bottom) {
        if(item->ch) {
            sprintf(buf,"%c %c %s",item->ch,(item->selected ? '+' : '-'),item->str);
        }else {
            sprintf(buf, "%s", item->str );
        }

        if(item->glyph != NO_GLYPH) {
            CopyRect(&rcGlyph, &rcItem);
            rcGlyph.right = rcGlyph.left + step;
            disp_procs.putGlyph(hdc, &rcGlyph, item->glyph);
            glyphOffset = step + 2;
        } else {
            glyphOffset = 0;
        }

        switch(item->attr) {
        case ATR_INVERSE:
        case ATR_BOLD:
            textColor = colormap[CLR_BRIGHT_CYAN];
            break;
        default:
            textColor = colormap[CLR_WHITE];
        }
        if(item->selected) {
            textColor = colormap[CLR_YELLOW];
        }
        SetTextColor(hdc, textColor);
        CopyRect(&rcTxt, &rcItem);
        rcTxt.left += glyphOffset;
        DrawText(hdc, buf, strlen(buf), &rcTxt,
            DT_LEFT|DT_SINGLELINE|DT_EXPANDTABS|DT_VCENTER|DT_NOPREFIX|DT_NOCLIP);
        if(PtInRect(&rcItem, pt) && mi->how != PICK_NONE && item->ch) {
            FrameRect(hdc, &rcItem, selBrs);
        }

        item = item->nmenu;
        rcItem.top = rcItem.bottom + 1;
        rcItem.bottom = rcItem.top + step;
    }

    SetBkColor(hdc, oldBkColor);
    SetTextColor(hdc, oldTextColor);
    SelectObject(hdc, oldFont);
    DeleteObject(selBrs);
}

/*-------------------------------------------------------------------------------------
 * WM_NCPAINT
 *-------------------------------------------------------------------------------------*/
static void MenuWnd_OnNCPaint(HWND hwnd, HRGN hrgn)
{
    WINDESC *wd = GETWINDESC(hwnd);
    WINMENUINFO *wmi;
    HDC hdc, dcMem;
    RECT rc, rcCaption;
    HPEN borderPen, oldPen;
    HBRUSH oldBrs;
    HFONT oldFont;
    int oldBkMode;
    COLORREF oldTextColor;
    HBITMAP oldBmp;
    char buf[BUFSZ];
    char *end_line;
    int font_width, font_height;

    wmi = (WINMENUINFO*)wd->pinfo;

    /* get device context */
    hdc = GetWindowDC(hwnd);
    /* get window rectangle */
    GetWindowRect(hwnd, &rc);
    /* get font metrics */
    font_width = Font_width(wmi->font, hdc);
    font_height = Font_height(wmi->font, hdc);

    /* Offset region and rectangle */
    if(hrgn != (HRGN)1) {
        SelectClipRgn(hdc, hrgn);
        OffsetClipRgn(hdc, -rc.left, -rc.top);
    }
    OffsetRect(&rc, -rc.left, -rc.top);
    borderPen = CreatePen(PS_SOLID|PS_INSIDEFRAME, BORDERWIDTH, colormap[CLR_GRAY]);
    dcMem = CreateCompatibleDC(hdc);
    oldBmp = SelectObject(dcMem, g_resource->btn_bmp);

    /* device context settings */
    oldBrs = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
    oldPen = SelectObject(hdc, borderPen);
    oldFont = SelectObject(hdc, wmi->font->font_handle);
    oldBkMode = SetBkMode(hdc, TRANSPARENT);
    oldTextColor = SetTextColor(hdc, colormap[CLR_YELLOW]);

    /* draw window frame */
    RoundRect(hdc, rc.left, rc.top, rc.right, rc.bottom, 20, 20);

    /* draw top line */
    rcCaption = rc;
    rcCaption.bottom = rcCaption.top + BORDERWIDTH * 2 + font_height + 2;
    rcCaption.left += (BORDERWIDTH);
    rcCaption.right -= (BORDERWIDTH);
    rcCaption.top += BORDERWIDTH;
    rcCaption.bottom -= BORDERWIDTH;

    rcCaption.left += 10;
    rcCaption.right -= 10;
    if(wd->wname) {
        DrawText(hdc, wd->wname, -1, &rcCaption, DT_LEFT|DT_SINGLELINE|DT_VCENTER);
    }
    sprintf(buf, "(%d/%d)", wmi->curpage, wmi->numpage);
    DrawText(hdc, buf, -1, &rcCaption, DT_RIGHT|DT_SINGLELINE|DT_VCENTER);

    /* Draw bottom line */
    rcCaption = rc;
    rcCaption.top = rcCaption.bottom - BORDERWIDTH*2 - font_height - 2;
    rcCaption.left += BORDERWIDTH;
    rcCaption.right -= BORDERWIDTH;
    rcCaption.top += BORDERWIDTH;
    rcCaption.bottom -= BORDERWIDTH;
    end_line = (wmi->curpage == wmi->numpage) ? STREND : STRMORE;
    DrawText(hdc, end_line, -1, &rcCaption, DT_CENTER|DT_SINGLELINE|DT_VCENTER);

    if(wmi->curpage < wmi->numpage ) {
        DrawText(hdc, ">>  ", -1, &rcCaption, DT_RIGHT|DT_SINGLELINE|DT_VCENTER);
    }
    if(wmi->curpage > 1) {
        DrawText(hdc, "  <<", -1, &rcCaption, DT_LEFT|DT_SINGLELINE|DT_VCENTER);
    }

    /* Restore Device Context settings */
    SelectObject(dcMem, oldBmp);
    SelectObject(hdc, oldPen);
    SelectObject(hdc, oldBrs);
    SelectObject(hdc, oldFont);
    SetBkMode(hdc, oldBkMode);
    SetTextColor(hdc, oldTextColor);

    /* Delete GDI Objects */
    DeleteObject(borderPen);
    DeleteDC(dcMem);

    /* Release Device Context */
    ReleaseDC(hwnd, hdc);
}

/***************************************************************************************
 * Initialize MenuWnd
 ***************************************************************************************/
BOOL MenuWnd_init(WINDESC *wd, int type)
{
    WINMENUINFO *wmi;

    wmi = (WINMENUINFO*)calloc(1, sizeof(WINMENUINFO));
    if(wmi) {
        wmi->property = &menu_property;
        wmi->font     = &menu_font;
        MenuWnd_setWindesc(wd, type, wmi);
        MenuWnd_clearElements(wd);
        return TRUE;
    }
    return FALSE;
}

/*-------------------------------------------------------------------------------------
 * Destructor
 *-------------------------------------------------------------------------------------*/
static void MenuWnd_procDestroy(WINDESC *wd)
{
    MenuWnd_clearItems(wd);
    free(wd->pinfo);
}

/*-------------------------------------------------------------------------------------
 * Update
 *-------------------------------------------------------------------------------------*/
static void MenuWnd_procDisplay(WINDESC *wd)
{
    MenuWnd_endMenu(wd,"");
    MenuWnd_selectMenu(wd, PICK_NONE, NULL);
}

/*-------------------------------------------------------------------------------------
 * Put string
 *-------------------------------------------------------------------------------------*/
static void MenuWnd_procPutStr( WINDESC *wd, int attr, const char *str )
{
    anything identifier;

    identifier.a_void = 0;
    MenuWnd_addMenu(wd, NO_GLYPH, &identifier, 0, 0, attr, str, FALSE);
}

/*-------------------------------------------------------------------------------------
 * Init members( for internal use only )
 *-------------------------------------------------------------------------------------*/
static void MenuWnd_clearElements(WINDESC *wd)
{
    WINMENUINFO *wmi = (WINMENUINFO*)wd->pinfo;

    wd->wname = NULL;
    wmi->how = PICK_NONE;
    wmi->selcount = 0;
    wmi->total = 0;
    wmi->canceled = FALSE;
    wmi->visible = 0;
    wmi->curpage = 0;
    wmi->numpage = 0;
    wmi->visible = 0;
    wmi->menu_first = NULL;
}

/*-------------------------------------------------------------------------------------
 * Clear items ( for internal use only )
 *-------------------------------------------------------------------------------------*/
static void MenuWnd_clearItems( WINDESC* wd )
{
    WINMENUINFO *wmi = (WINMENUINFO*)wd->pinfo;
    WINMENUITEM *tmpitem;
    WINMENUITEM *delitem;

    delitem = wmi->menu_first;
    while(delitem) {
        tmpitem = delitem->nmenu;
        if(delitem->str) {
            free(delitem->str);
        }
        free(delitem);
        delitem = tmpitem;
    }
    if(wd->wname) {
        free(wd->wname);
    }
}

/*-------------------------------------------------------------------------------------
 * 
 *-------------------------------------------------------------------------------------*/
static void MenuWnd_processKey(HWND hwnd)
{
    WINDESC *wd;
    WINMENUINFO *wmi;
    WINMENUITEM *item;
    int  ch;
    int  i;
    BOOL done;
    BOOL reNC;
    BOOL reCL;

    wd = (WINDESC*)GetWindowLong(hwnd,GWL_USERDATA);
    wmi = (WINMENUINFO*)wd->pinfo;
    wmi->done = FALSE;
    while(!wmi->done) {
        reNC = FALSE;
        reCL = FALSE;
        ch = map_menu_cmd(Key_getChar());
        switch(ch) {
        case MENU_FIRST_PAGE:
            if(wmi->curpage!=1) {
                wmi->curpage=1;
                reNC=reCL=TRUE;
            }
            break;
        case MENU_LAST_PAGE:
            if(wmi->curpage != wmi->numpage) {
                wmi->curpage = wmi->numpage;
                reNC=reCL=TRUE;
            }
            break;
        case MENU_NEXT_PAGE:
            if(wmi->curpage < wmi->numpage) {
                wmi->curpage++;
                reNC=reCL=TRUE;
            }
            break;
        case MENU_PREVIOUS_PAGE:
            if(wmi->curpage > 1) {
                wmi->curpage--;
                reNC=reCL=TRUE;
            }
            break;
        case MENU_SELECT_ALL:
            if(wmi->how == PICK_ANY) {
                wmi->selcount=0;
                for(item=wmi->menu_first; item!=NULL; item=item->nmenu) {
                    if(item->identifier.a_void != 0 && item->ch != 0) {
                        item->selected = TRUE;
                        item->count = -1;
                        wmi->selcount++;
                    }
                }
                reCL=TRUE;
            }
            break;
        case MENU_UNSELECT_ALL:
            if(wmi->how==PICK_ANY) {
                item = wmi->menu_first;
                for(i=0; item!=NULL; i++,item=item->nmenu) {
                    item->selected = FALSE;
                    item->count = 0;
                }
                wmi->selcount = 0;
                reCL=TRUE;
            }
            break;
        case MENU_INVERT_ALL:
            if(wmi->how == PICK_ANY) {
                wmi->selcount = 0;
                for(item=wmi->menu_first;item!=NULL;item=item->nmenu) {
                    if(item->identifier.a_void != 0 && item->ch != 0) {
                        item->selected = !item->selected;
                        if(item->selected) {
                            item->count = -1;
                            wmi->selcount++;
                        }else {
                            item->count = 0;
                        }
                    }
                }
                reCL=TRUE;
            }
            break;
        case MENU_SELECT_PAGE:
            if(wmi->how == PICK_ANY) {
                item = wmi->menu_first;
                for(i=0; i<(wmi->curpage-1)*wmi->visible;i++,item=item->nmenu);
                for(i=0; i<wmi->visible && item!=NULL; i++,item=item->nmenu) {
                    if(item->identifier.a_void != 0 && item->ch != 0) {
                        item->selected = TRUE;
                        item->count = -1;
                    }
                }
                wmi->selcount=0;
                for(item=wmi->menu_first;item != NULL;item=item->nmenu) {
                    if(item->selected) {
                        wmi->selcount++;
                    }
                }
                reCL=TRUE;
            }
            break;
        case MENU_UNSELECT_PAGE:
            if(wmi->how == PICK_ANY) {
                item = wmi->menu_first;
                for(i=0; i<(wmi->curpage-1)*wmi->visible;i++,item=item->nmenu);
                for(i=0; i<wmi->visible && item!=NULL; i++,item=item->nmenu) {
                    item->selected = FALSE;
                    item->count = 0;
                }
                wmi->selcount=0;
                for(item=wmi->menu_first;item != NULL; item=item->nmenu) {
                    if(item->selected) {
                        wmi->selcount++;
                    }
                }
                reCL=TRUE;
            }
            break;
        case MENU_INVERT_PAGE:
            if(wmi->how == PICK_ANY) {
                item = wmi->menu_first;
                for(i=0; i<(wmi->curpage-1)*wmi->visible;i++,item=item->nmenu);
                for(i=0; i<wmi->visible && item!=NULL; i++,item=item->nmenu) {
                    if(item->identifier.a_void != 0 && item->ch != 0) {
                        item->selected = !item->selected;
                        if(item->selected) {
                            item->count = -1;
                        }else {
                            item->count = 0;
                        }
                    }
                }
                wmi->selcount=0;
                for(item=wmi->menu_first; item != NULL; item=item->nmenu) {
                    if(item->selected) {
                        wmi->selcount++;
                    }
                }
                reCL=TRUE;
            }
            break;
        case MENU_SEARCH:
            /* Not supported */
            break;
        case VK_ESCAPE:
            wmi->canceled = TRUE;
            wmi->done = TRUE;
            break;
        case VK_RETURN:
            wmi->done = TRUE;
            break;
        case VK_SPACE:
            wmi->curpage++;
            if(wmi->curpage > wmi->numpage) {
                wmi->done = TRUE;
            }else {
                reNC=reCL=TRUE;
            }
            break;
        default:
            if(wmi->how != PICK_NONE) {
                done = FALSE;
                item = wmi->menu_first;
                for(i=0; i<(wmi->curpage-1)*wmi->visible;i++,item=item->nmenu);
                for(i=0; i<wmi->visible && item!=NULL; i++,item=item->nmenu) {
                    if(item->ch == ch || item->gch == ch) {
                        item->selected = !item->selected;
                        if(item->selected) {
                            item->count = -1;
                            wmi->selcount++;
                            done = TRUE;
                        }else {
                            item->count = 0;
                            wmi->selcount--;
                        }
                        reCL=TRUE;
                    }
                }
                if(done && wmi->how == PICK_ONE) {
                    wmi->done = TRUE;
                }
            }
            break;
        }
        if(reNC) {
            SetWindowPos(hwnd,0,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
        }
        if(reCL) {
            InvalidateRect(hwnd,NULL,TRUE);
        }
    }
}

/***************************************************************************************
 * start_menu
 ***************************************************************************************/
void MenuWnd_startMenu(WINDESC *wd)
{
    MenuWnd_clearItems(wd);
    MenuWnd_clearElements(wd);

    if(wd->hwnd != NULL) {
        DestroyWindow(wd->hwnd);
        wd->hwnd = NULL;
    }
}

/***************************************************************************************
 * add_menu
 ***************************************************************************************/
BOOL MenuWnd_addMenu(
    WINDESC *wd,
    int glyph,
    const anything *identifier,
    char ch,
    char gch,
    int attr,
    const char *str,
    boolean preselected)
{
    WINMENUINFO *wmi = (WINMENUINFO*)wd->pinfo;
    WINMENUITEM **menuitem;
    char *tmp;

    if(str) {
        tmp = (char *)calloc(strlen(str)+1, sizeof(char));
        strcpy( tmp, str );
    }else {
        tmp = (char *)0;
    }

    menuitem = &wmi->menu_first;
    while( (*menuitem) != NULL ) {
        menuitem = &(*menuitem)->nmenu;
    }
    (*menuitem) = (WINMENUITEM*)calloc(1, sizeof(WINMENUITEM));
    (*menuitem)->glyph = glyph;
    (*menuitem)->identifier = *identifier;
    (*menuitem)->ch = ch;
    (*menuitem)->gch = gch;
    (*menuitem)->attr = attr;
    (*menuitem)->str = tmp;
    (*menuitem)->nmenu = NULL;
    (*menuitem)->selected = preselected;
    (*menuitem)->count = 0;

    wmi->total++;

    return TRUE;
}

/***************************************************************************************
 * end_menu
 ***************************************************************************************/
void MenuWnd_endMenu(WINDESC *wd, const char *prompt)
{
    WINMENUINFO *wmi = (WINMENUINFO*)wd->pinfo;
    WINMENUITEM *mitem;
    int i, j, junk;
    boolean sflag;

    mitem = wmi->menu_first;

    for (i = 0, j = 'a', junk = 0; mitem != NULL; mitem = mitem->nmenu) {
        sflag = FALSE;
        if( mitem->str ) {
            if ( mitem->identifier.a_void ) {
                if ( !mitem->ch ) {
                    mitem->ch = j++;
                }
            }
        }
        if( j > 'z' ) {
            j = 'A';
        }
        if( (j > 'Z') && (j < 'a') ) {
            j = '?';
        }
    }

    if( !prompt ) {
        prompt = "Nethack Menu";
    }

    wd->wname = (char*)calloc(strlen(prompt)+1, sizeof(char));
    strcpy(wd->wname, prompt);
}

/***************************************************************************************
 * select_menu
 ***************************************************************************************/
int MenuWnd_selectMenu(WINDESC *wd, int how, menu_item **menu_list)
{
    WINMENUINFO* wmi = (WINMENUINFO*)wd->pinfo;
    WINMENUITEM* mitem;
    int mind;

    wmi->how = how;
    wd->hwnd = CreateWindowEx(
        wd->exstyle,
        wd->cname,
        wd->wname,
        wd->style,
        0,
        0,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        g_baseHwnd,
        (HMENU)NULL,
        g_hInstance,
        (LPVOID)wd);

    MenuWnd_calcRect(wd);
    NHWnd_moveCenter(wd->hwnd, g_baseHwnd);
    ShowWindow(wd->hwnd, SW_SHOW);

    MenuWnd_processKey(wd->hwnd);

    DestroyWindow( wd->hwnd );
    wd->hwnd = NULL;

    if(how == PICK_NONE) {
        return 0;
    }
    if(wmi->canceled) {
        return -1;
    }

    if(wmi->selcount > 0) {
        mind = 0;
        (*menu_list) = (menu_item*)alloc( wmi->selcount * sizeof(menu_item));
        mitem = wmi->menu_first;
        while(mitem) {
            if(mitem->selected) {
                (*menu_list + mind)->item.a_void = mitem->identifier.a_void;
                (*menu_list + mind)->count = mitem->count;
                mind++;
            }
            mitem = mitem->nmenu;
        }
    }

    return wmi->selcount;
}


/*-------------------------------------------------------------------------------------
 * Menu window property dialog procedure
 *-------------------------------------------------------------------------------------*/
static BOOL CALLBACK MenuPropProc(HWND hDlg, UINT mesg, UINT wParam, LONG lParam)
{
    static FONTINFO font;
    static FONTINFO *ptr;

    switch (mesg) {
    case WM_INITDIALOG:

        /* Set initial values */
        ptr = (FONTINFO *)lParam;
        CopyMemory(&font, ptr, sizeof(FONTINFO));
        SendDlgItemMessage(hDlg, STATIC_FONT, WM_SETFONT, (WPARAM)font.font_handle, 0);
        break;

    case WM_CTLCOLORSTATIC:

        /* Set sample font color */
        if((HWND)lParam == GetDlgItem(hDlg, STATIC_FONT)) {
            SetTextColor((HDC)wParam, font.font_color);
            SetBkMode((HDC)wParam, TRANSPARENT);
            return (BOOL)GetStockObject(BLACK_BRUSH);
        } else {
            return DefWindowProc(hDlg, mesg, wParam, lParam);
        }
        break;

    case WM_COMMAND:
        switch (LOWORD(wParam)) {
        case IDOK:

            /* Save settings */
            CopyMemory(ptr, &font, sizeof(FONTINFO));
            EndDialog(hDlg, 1);
            break;

        case IDCANCEL:

            /* Dialog canceled */
            Font_delete(&font);
            Font_create(ptr);
            EndDialog(hDlg, 0);
            break;

        case BUTTON_FONT:

            /* Show font dialog */
            Font_select(hDlg, &font, TRUE, FALSE, TRUE);
            SendDlgItemMessage(
                hDlg, STATIC_FONT, WM_SETFONT, (WPARAM)font.font_handle, MAKELPARAM(TRUE, 0));
            break;

        case BUTTON_RESET:

            /* Restore previous values */
            Font_delete(&font);
            CopyMemory(&font, ptr, sizeof(FONTINFO));
            Font_create(&font);
            SendDlgItemMessage(
                hDlg, STATIC_FONT, WM_SETFONT, (WPARAM)font.font_handle, MAKELPARAM(TRUE, 0));
            break;

        default:
            break;
        }
        break;
    default:
        return FALSE;
    }
    return TRUE;
}

/***************************************************************************************
 * Display property dialog
 ***************************************************************************************/
void MenuWnd_cmdProperty()
{
    /* Property dialog open */
    if(DialogBoxParam(g_hInstance, "MENU_PROP", g_baseHwnd, MenuPropProc, (LPARAM)&menu_font)) {

        /* "OK" button pressed */
        MenuWnd_saveProperty(&menu_property, g_propFile);
        Font_save(&menu_font, g_propFile, "MenuWnd");
        NHWnd_newLayout();
    }
}

/*-------------------------------------------------------------------------------------
 * Save current settings to ini file
 *-------------------------------------------------------------------------------------*/
static void MenuWnd_saveProperty(WINMENUPROP *property, char *filename)
{
    WritePrivateProfileStruct(
        "MenuWnd", "Property", property, sizeof(WINMENUPROP), filename);
}

/*-------------------------------------------------------------------------------------
 * Load settings from ini file 
 *-------------------------------------------------------------------------------------*/
static void MenuWnd_loadProperty(WINMENUPROP *property, char *filename)
{
    if(!GetPrivateProfileStruct(
        "MenuWnd", "Property", property, sizeof(WINMENUPROP), filename)) {

        /* failed to load, set default values */
        property->max_lines      = 20;
        property->glyph_fit_font = FLAG_ON;
        property->glyph_width    = 16;
        property->glyph_height   = 16;
    }
}

/***************************************************************************************
 * 
 ***************************************************************************************/
void MenuWnd_setDefault()
{
    /* create fonts */
    Font_load(&menu_font, g_propFile, "MenuWnd");
    MenuWnd_loadProperty(&menu_property, g_propFile);
}

/*-------------------------------------------------------------------------------------
 * WM_LBUTTONDOWN
 *-------------------------------------------------------------------------------------*/
void MenuWnd_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
{
    WINDESC     *wd = GETWINDESC(hwnd);
    WINMENUINFO *wmi = wd->pinfo;
    WINMENUITEM *item;
    POINT        pt;
    RECT         rcWnd, rcItem;
    HDC          hdc;
    int          i, step;

    if(wmi->how == PICK_NONE) {
        return;
    }
    
    GetCursorPos(&pt);
    ScreenToClient(hwnd, &pt);
    GetClientRect(hwnd, &rcWnd);
    hdc = GetDC(hwnd);
    step = Font_height(wmi->font, hdc);
    step--;
    ReleaseDC(hwnd, hdc);

    CopyRect(&rcItem, &rcWnd);
    rcItem.bottom = rcItem.top + step;
    item = wmi->menu_first;

    /* skip */
    for(i = 0; i < (wmi->curpage-1) * wmi->visible; i++, item = item->nmenu);
    while(item && rcItem.top < rcWnd.bottom) {
        if(item->ch && PtInRect(&rcItem, pt)) {
            Key_put(item->ch);
            break;
        }
        item = item->nmenu;
        rcItem.top = rcItem.bottom + 1;
        rcItem.bottom = rcItem.top + step;
    }
}

#endif /* NH2K_EXTENDS */
