/*
 * w_map.c : main map window related routines (NHW_MAP)
 *
 * 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"

/*
 * Map window property
 */
typedef struct tagWINMAPPROP{
    int micro_x;
    int micro_y;
    int micro_width;
    int micro_height;
    short tile_width;
    short tile_height;
    BYTE draw_type;
    BYTE show_micro;
    BYTE show_tile;
    BYTE show_effect;
    BYTE effect_delay;
}WINMAPPROP;

/*
 * Map window data
 */
typedef struct tagWINMAPINFO{
    HDRAWDIB    hdd;
    OFFSCREEN  *ofb;
    HWND        sub_wnd;
    WINMAPPROP  property;
    FONTINFO    font;
    BYTE        types[ROWNO][COLNO];
    char        text[ROWNO][COLNO];     /* symbol buffer */
    int         color[ROWNO][COLNO];    /* color buffer */
}WINMAPINFO;

/*
 * local function declarations
 */
static void FDECL(MapWnd_setWindesc, (WINDESC *,int,void *));
static void FDECL(MapWnd_procDraw, (WINDESC*,HDC));
static void FDECL(MapWnd_procCalcRect, (WINDESC*,RECT*,RECT*));
static void FDECL(MapWnd_procDestroy, (WINDESC *));
static void FDECL(MapWnd_procDisplay, (WINDESC *));
static void FDECL(MapWnd_procClear, (WINDESC*));
static void FDECL(MapWnd_procSetCursor, (WINDESC *, int, int));
static BOOL FDECL(MapWnd_OnCreate, (HWND hwnd,LPCREATESTRUCT lpCS ));
static HWND FDECL(MicroWnd_create, (WINDESC *));
static void FDECL(MicroWnd_draw, (WINMAPINFO *,HDC,BOOL));
static BOOL CALLBACK FDECL(MapPropProc, (HWND,UINT,UINT,LONG));
static void FDECL(MapWnd_defaultProperty, (void *));
static void FDECL(MapWnd_textOut, (WINDESC *,HDC));

/***************************************************************************************/
/* Initialize
/***************************************************************************************/
BOOL MapWnd_init(WINDESC *wd, int type)
{
    WINMAPINFO  *wmi;

    wmi = (WINMAPINFO*)calloc(1, sizeof(WINMAPINFO));
    if(wmi) {

        /* load settings from file */
        NHWnd_loadProperty(
            "MapWnd", &wmi->property, sizeof(WINMAPPROP), MapWnd_defaultProperty);

        Font_load(&wmi->font, g_propFile, "MapWnd");

        /* load bitmap for micro map */
        wmi->ofb = Offscreen_create(
            g_resource->sym_bmp->width * COLNO,
            g_resource->sym_bmp->height * ROWNO,
            g_resource->sym_bmp->hpal);

        wmi->hdd = DrawDibOpen();

        /* set window descriptor */
        MapWnd_setWindesc(wd, type, wmi);
        MapWnd_procClear(wd);

        return TRUE;
    }

    return FALSE;
}

/***************************************************************************************/
/* Main map window procedure
/***************************************************************************************/
LRESULT CALLBACK MapWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
    switch(msg) {
        HANDLE_MSG(hwnd, WM_NCCREATE,   NHWnd_OnCreate);
        HANDLE_MSG(hwnd, WM_ERASEBKGND, NHWnd_OnEraseBkgnd);
        HANDLE_MSG(hwnd, WM_PAINT,      NHWnd_OnPaint);
        HANDLE_MSG(hwnd, WM_CREATE,     MapWnd_OnCreate);
    default:
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
}

/*--------------------------------------------------------------------------------------
 *
 *-------------------------------------------------------------------------------------*/
static BOOL MapWnd_OnCreate(HWND hwnd, LPCREATESTRUCT lpCS )
{
    WINDESC *wd = GETWINDESC(hwnd);
    WINMAPINFO *wmi = (WINMAPINFO*)wd->pinfo;

    /* Create micro map window */
    wmi->sub_wnd = MicroWnd_create(wd);

    return TRUE;
}

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

    wd->procCalcRect   = MapWnd_procCalcRect;
    wd->procDestroy    = MapWnd_procDestroy;
    wd->procDisplay    = MapWnd_procDisplay;
    wd->procClear      = MapWnd_procClear;
    wd->procSetCursor  = MapWnd_procSetCursor;
    wd->procPutStr     = NULL;
    wd->procDraw       = MapWnd_procDraw;
}

/*--------------------------------------------------------------------------------------
 *
 *-------------------------------------------------------------------------------------*/
static void MapWnd_procDestroy(WINDESC* wd)
{
    WINMAPINFO *wmi = (WINMAPINFO*)wd->pinfo;

    if(wmi) {
        if(wmi->hdd) {
            DrawDibClose(wmi->hdd);
        }
        if(wmi->ofb) {
            Offscreen_free(wmi->ofb);
        }
        if(wmi->sub_wnd) {
            DestroyWindow(wmi->sub_wnd);
        }
        Font_delete(&wmi->font);
        free(wmi);
    }
}

/*--------------------------------------------------------------------------------------
 *
 *-------------------------------------------------------------------------------------*/
static void MapWnd_procDisplay(WINDESC *wd)
{
    WINMAPINFO *wmi = (WINMAPINFO*)wd->pinfo;
    HDC hdc;

    /* update glyphs */
    disp_procs.updateGlyph();
    NHWnd_display(wd);

    /* update micro map */
    if(wmi->sub_wnd) {
        Offscreen_blt(wmi->ofb,
            g_resource->sym_bmp->width * u.ux,
            g_resource->sym_bmp->height * u.uy,
            g_resource->sym_bmp->width,
            g_resource->sym_bmp->height,
            &g_resource->sym_bmp->tiles[PLACE_YOU],
            0, 0, BLTMODE_COPY);
        hdc = GetDC(wmi->sub_wnd);
        MicroWnd_draw(wmi, hdc, FALSE);
        ReleaseDC(wmi->sub_wnd, hdc);
    }

}

/*--------------------------------------------------------------------------------------
 *
 *-------------------------------------------------------------------------------------*/
static void MapWnd_procClear(WINDESC* wd)
{
    WINMAPINFO *wmi = (WINMAPINFO*)wd->pinfo;
    int row, col;

    disp_procs.clear();
    Offscreen_clear(wmi->ofb);
    for(row = 0; row < ROWNO; row++) {
        for(col = 0; col < COLNO; col++) {
            wmi->types[row][col] = PLACE_NON;
            wmi->color[row][col] = INVALID_GLYPH;
        }
    }
}

/*--------------------------------------------------------------------------------------
 *
 *-------------------------------------------------------------------------------------*/
static void MapWnd_procCalcRect(WINDESC *wd, RECT *rcParent, RECT *rcMove)
{
    WINMAPINFO *wmi = (WINMAPINFO*)wd->pinfo;
    int cx, cy;
    HDC hdc;

    CopyRect(rcMove, rcParent);
    rcMove->left += 30;
    rcMove->top += 6;
    rcMove->right -= 30;
    rcMove->bottom -= 6;

    if(wmi->property.show_tile) {       /* tile mode */
        if(disp_procs.getRect) {
            disp_procs.getRect(rcMove);
        }
    } else {                             /* text mode */

        /* calculate logical font size */
        wmi->font.font_width  = (rcMove->right - rcMove->left) / COLNO;
        wmi->font.font_height = (rcMove->bottom - rcMove->top) / ROWNO;

        /* create new font */
        Font_create(&wmi->font);

        /* calculate window size */
        hdc = GetDC(wd->hwnd);
        cx = Font_width(&wmi->font, hdc) * COLNO;
        cy = Font_height(&wmi->font, hdc) * ROWNO;
        rcMove->left += ((rcMove->right - rcMove->left) - cx) / 2;
        rcMove->top  += ((rcMove->bottom - rcMove->top) - cy) / 2;
        rcMove->right = rcMove->left + cx;
        rcMove->bottom = rcMove->top + cy;

        ReleaseDC(wd->hwnd, hdc);
    }
}

/***************************************************************************************/
/* Put glyph
/***************************************************************************************/
void MapWnd_setGlyph(WINDESC *wd, int col, int row, int back, int fore)
{
    WINMAPINFO *wmi = (WINMAPINFO*)wd->pinfo;
    TILEDATA *tile;
    int color;
    int glyph = (fore != cmap_to_glyph(S_stone)) ? fore : back;

    disp_procs.printGlyph(col, row, back, fore);

    /* update micro map */
    if(wmi->types[row][col] != Glyph_toType(glyph)) {
        wmi->types[row][col] = Glyph_toType(glyph);
        tile = &g_resource->sym_bmp->tiles[wmi->types[row][col]];
        Offscreen_blt(wmi->ofb,
            tile->cx * col,
            tile->cy * row,
            tile->cx,
            tile->cy,
            tile,
            0,
            0,
            BLTMODE_COPY);
    }

    /* update text and color */
    if(glyph == cmap_to_glyph(S_stone)) {
        wmi->color[row][col] = INVALID_GLYPH;
    } else {
        wmi->text[row][col] = Glyph_toChar(glyph, &color);
        wmi->color[row][col] = color;
    }
}

/*--------------------------------------------------------------------------------------
 *
 *-------------------------------------------------------------------------------------*/
static void MapWnd_procSetCursor(WINDESC *wd, int x, int y)
{
    WINMAPINFO *wmi = (WINMAPINFO *)wd->pinfo;
    
    if(wd->cur.x >= 0 && wd->cur.y >= 0) {
        Offscreen_blt(wmi->ofb,
            g_resource->sym_bmp->width * wd->cur.x,
            g_resource->sym_bmp->height * wd->cur.y,
            g_resource->sym_bmp->width,
            g_resource->sym_bmp->height,
            &g_resource->sym_bmp->tiles[wmi->types[wd->cur.y][wd->cur.x]],
            0, 0, BLTMODE_COPY);
    }
    wd->cur.x = x;
    wd->cur.y = y;
    disp_procs.setCursor(wd->cur);
    Offscreen_blt(wmi->ofb,
        g_resource->sym_bmp->width * x,
        g_resource->sym_bmp->height * y,
        g_resource->sym_bmp->width,
        g_resource->sym_bmp->height,
        &g_resource->sym_bmp->tiles[PLACE_CUR],
        0, 0, BLTMODE_MASK);
}

/*--------------------------------------------------------------------------------------
 *
 *-------------------------------------------------------------------------------------*/
static void MapWnd_textOut(WINDESC *wd, HDC hdc)
{
    WINMAPINFO *wmi = (WINMAPINFO *)wd->pinfo;
    RECT        rcWnd, rcText;
    int         x, y, cx, cy;
    char        buf[2];
    COLORREF    oldColor;
    HFONT       oldFont;

    buf[1] = '\0';
    GetClientRect(wd->hwnd, &rcWnd);
    cx = (rcWnd.right - rcWnd.left) / COLNO;
    cy = (rcWnd.bottom - rcWnd.top) / ROWNO;

    oldFont  = SelectObject(hdc, wmi->font.font_handle);
    oldColor = SetBkColor(hdc, colormap[CLR_BLACK]);

    for(y = 0; y < ROWNO; y++) {
        for(x = 0; x < COLNO; x++) {
            rcText.top    = y * cy;
            rcText.left   = x * cx;
            rcText.right  = rcText.left + cx;
            rcText.bottom = rcText.top + cy;
            if(wmi->color[y][x] != INVALID_GLYPH) {
                buf[0] = wmi->text[y][x];
                SetTextColor(hdc, colormap[wmi->color[y][x]]);
                ExtTextOut(
                    hdc, rcText.left, rcText.top, ETO_OPAQUE, &rcText, buf, 1, NULL);
            } else {
                ExtTextOut(
                    hdc, rcText.left, rcText.top, ETO_OPAQUE, &rcText, NULL, 0, NULL);
            }
        }
    }
    /* draw cursor */
    rcText.left   = wd->cur.x * cx;
    rcText.top    = (wd->cur.y + 1) * cy - 4;
    rcText.right  = rcText.left + cx;
    rcText.bottom = rcText.top + 3;
    FillRect(hdc, &rcText, GetStockObject(WHITE_BRUSH));

    SelectObject(hdc, oldFont);
    SetBkColor(hdc, oldColor);
}

/*--------------------------------------------------------------------------------------
 *
 *-------------------------------------------------------------------------------------*/
static void MapWnd_procDraw(WINDESC *wd, HDC hdc)
{
    WINMAPINFO *wmi = ((WINDESC*)WIN_MAP)->pinfo;

    if(wmi->property.show_tile) {       /* tile mode */
        disp_procs.setDispMode(
            wmi->property.draw_type,
            wmi->property.tile_width,
            wmi->property.tile_height);
        disp_procs.draw(wd->hwnd, hdc, FALSE);
    } else {                            /* text mode */
        MapWnd_textOut(wd, hdc);
    }
}

/*-------------------------------------------------------------------------------------
 * Load settings from ini file 
 *-------------------------------------------------------------------------------------*/
static void MapWnd_defaultProperty(void *param)
{
    WINMAPPROP *property = (WINMAPPROP *)param;

    property->show_tile    = FALSE;
    property->draw_type    = D_DEFAULT;
    property->show_micro   = FLAG_OFF;
    property->micro_x      = 0;
    property->micro_y      = 0;
    property->micro_width  = 0;
    property->micro_height = 0;
    property->tile_width   = 1;
    property->tile_height  = 1;
    property->show_effect  = FLAG_ON;
    property->effect_delay = 10;
}

/*-------------------------------------------------------------------------------------
 * 
 *-------------------------------------------------------------------------------------*/
static HWND MicroWnd_create(WINDESC *wd)
{
    WINMAPINFO *wmi = (WINMAPINFO *)wd->pinfo;
    DWORD exstyle   = WS_EX_TOOLWINDOW;
    DWORD style = WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME;
    RECT rc;

    rc.left   = 0;
    rc.top    = 0;
    rc.right  = wmi->property.micro_width > 0 ? wmi->property.micro_width
        : g_resource->sym_bmp->width * COLNO;
    rc.bottom = wmi->property.micro_height > 0 ? wmi->property.micro_height
        : g_resource->sym_bmp->height * ROWNO;
    AdjustWindowRectEx(&rc, style, FALSE, exstyle);
    style |= (wmi->property.show_micro ? WS_VISIBLE : 0);

    return CreateWindowEx(
        exstyle,
        "NHMICRO",
        "NetHack Micro Map",
        style,
        wmi->property.micro_x,
        wmi->property.micro_y,
        rc.right - rc.left,
        rc.bottom - rc.top,
        g_baseHwnd,
        (HMENU)0,
        g_hInstance,
        (LPVOID)wd);
}

/*-------------------------------------------------------------------------------------
 * WM_PAINT
 *-------------------------------------------------------------------------------------*/
static void MicroWnd_OnPaint(HWND hwnd)
{
    WINDESC    *wd = GETWINDESC(hwnd);
    WINMAPINFO *wmi = (WINMAPINFO *)wd->pinfo;
    PAINTSTRUCT ps;
    HDC         hdc;

    hdc = BeginPaint(hwnd, &ps);
    MicroWnd_draw(wmi, hdc, TRUE);
    EndPaint(hwnd, &ps);
}

/*-------------------------------------------------------------------------------------
 * WM_MOVE
 *-------------------------------------------------------------------------------------*/
static void MicroWnd_OnMove(HWND hwnd, int x, int y)
{
    WINDESC    *wd = GETWINDESC(hwnd);
    WINMAPINFO *wmi = (WINMAPINFO *)wd->pinfo;
    RECT        rc;

    GetWindowRect(hwnd, &rc);
    wmi->property.micro_x = rc.left;
    wmi->property.micro_y = rc.top;
    NHWnd_saveProperty("MapWnd", &wmi->property, sizeof(WINMAPPROP));
}

/*-------------------------------------------------------------------------------------
 * WM_SIZE
 *-------------------------------------------------------------------------------------*/
static void MicroWnd_OnSize(HWND hwnd, UINT state, int cx, int cy)
{
    WINDESC    *wd = GETWINDESC(hwnd);
    WINMAPINFO *wmi = (WINMAPINFO *)wd->pinfo;

    InvalidateRect(hwnd, NULL, FALSE);
    wmi->property.micro_width = cx;
    wmi->property.micro_height = cy;
    NHWnd_saveProperty("MapWnd", &wmi->property, sizeof(WINMAPPROP));
}

/*-------------------------------------------------------------------------------------
 * WM_MOUSEMOVE
 *-------------------------------------------------------------------------------------*/
static void MicroWnd_OnMouseMove(HWND hwnd, int x, int y, UINT flags)
{
    WINDESC *wd = GETWINDESC(hwnd);
    RECT     rc;

    if(GetCapture() == hwnd) {
        GetClientRect(hwnd, &rc);
        if(x < 0)         x = 0;
        if(x > rc.right)  x = rc.right;
        if(y < 0)         y = 0;
        if(y > rc.bottom) y = rc.bottom;
        disp_procs.setViewPoint(VIEWPOINT_SET,
            x * 100 / (rc.right - rc.left),
            y * 100 / (rc.bottom - rc.top));
        NHWnd_display(wd);
    }
}

/*-------------------------------------------------------------------------------------
 * WM_LBUTTONDOWN
 *-------------------------------------------------------------------------------------*/
static void MicroWnd_OnLButtonDown(HWND hwnd, BOOL fDC, int x, int y, UINT flags)
{
    SetCapture(hwnd);
    MicroWnd_OnMouseMove(hwnd, x, y, flags);
}

/*-------------------------------------------------------------------------------------
 * WM_LBUTTONUP
 *-------------------------------------------------------------------------------------*/
static void MicroWnd_OnLButtonUp(HWND hwnd, int x, int y, UINT flags)
{
    WINDESC *wd = GETWINDESC(hwnd);

    if(GetCapture() == hwnd) {
        if(disp_procs.setViewPoint) {
            disp_procs.setViewPoint(VIEWPOINT_CLEAR, 0, 0);
            NHWnd_display(wd);
        }
        ReleaseCapture();
    }
}

/*-------------------------------------------------------------------------------------
 * WM_COMMAND
 *-------------------------------------------------------------------------------------*/
static void MicroWnd_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
    WINDESC    *wd = GETWINDESC(hwnd);
    WINMAPINFO *wmi = (WINMAPINFO *)wd->pinfo;

    switch (id) {
    case IDCANCEL:
        ShowWindow(hwnd, SW_HIDE);
        wmi->property.show_micro = FLAG_OFF;
        break;
    default:
        break;
    }
}

/*-------------------------------------------------------------------------------------
 * WM_CLOSE
 *-------------------------------------------------------------------------------------*/
static void MicroWnd_OnClose(HWND hwnd)
{
    WINDESC    *wd = GETWINDESC(hwnd);
    WINMAPINFO *wmi = (WINMAPINFO *)wd->pinfo;

    ShowWindow(hwnd, SW_HIDE);
    wmi->property.show_micro = FLAG_OFF;
}

/*-------------------------------------------------------------------------------------
 * Micro map(rader) window procedure
 *-------------------------------------------------------------------------------------*/
LRESULT CALLBACK MicroWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg) {
        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_CREATE,      NHWnd_OnCreate);
        HANDLE_MSG(hwnd, WM_ERASEBKGND,  NHWnd_OnEraseBkgnd);
        HANDLE_MSG(hwnd, WM_PAINT,       MicroWnd_OnPaint);
        HANDLE_MSG(hwnd, WM_SIZE,        MicroWnd_OnSize);
        HANDLE_MSG(hwnd, WM_MOVE,        MicroWnd_OnMove);
        HANDLE_MSG(hwnd, WM_LBUTTONDOWN, MicroWnd_OnLButtonDown);
        HANDLE_MSG(hwnd, WM_LBUTTONUP,   MicroWnd_OnLButtonUp);
        HANDLE_MSG(hwnd, WM_MOUSEMOVE,   MicroWnd_OnMouseMove);
        HANDLE_MSG(hwnd, WM_CLOSE,       MicroWnd_OnClose);
    default:
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
}

/*--------------------------------------------------------------------------------------
 * Draw micro map
 *-------------------------------------------------------------------------------------*/
static void MicroWnd_draw(WINMAPINFO *wmi, HDC hdc, BOOL fForce)
{
    HDC     dc_mem;
    HBITMAP old_bmp;
    RECT    rc;
    int     cx, cy;

    GetClientRect(wmi->sub_wnd, &rc);
    
    /* Draw map */
    cx = rc.right - rc.left;
    cy = rc.bottom - rc.top;
    if(cx == g_resource->sym_bmp->width * COLNO && cy == g_resource->sym_bmp->height * ROWNO) {
        dc_mem = CreateCompatibleDC(hdc);
        old_bmp = SelectObject(dc_mem, wmi->ofb->hbmp);
        BitBlt(hdc, 0, 0, cx, cy, dc_mem, 0, 0, SRCCOPY);
        SelectObject(dc_mem, old_bmp);
        DeleteDC(dc_mem);
    }else if(wmi->hdd) {
        DrawDibDraw(
            wmi->hdd,hdc,rc.left,rc.top,rc.right - rc.left,rc.bottom - rc.top,
            wmi->ofb->info,wmi->ofb->bits,0,0,wmi->ofb->info->biWidth,wmi->ofb->info->biHeight,0);
    }else {
        dc_mem = CreateCompatibleDC(hdc);
        old_bmp = SelectObject(dc_mem, wmi->ofb->hbmp);
        StretchBlt(hdc, 0, 0, cx, cy, 
            dc_mem, 0, 0, wmi->ofb->info->biWidth, wmi->ofb->info->biHeight, SRCCOPY);
        SelectObject(dc_mem, old_bmp);
        DeleteDC(dc_mem);
    }
}

/*-------------------------------------------------------------------------------------
 * Display property dialog
 *-------------------------------------------------------------------------------------*/
void MapWnd_cmdProperty(WINDESC *wd)
{
    WINMAPINFO *wmi;
    int keyStat;
    
    if(!NHWnd_isValid(wd)) {
        return;
    }

    keyStat = Key_setStatus(KEYSTAT_DIALOGINPUT);

    wmi = (WINMAPINFO *)wd->pinfo;
    if(DialogBoxParam(g_hInstance, "MAP_PROP", g_baseHwnd, MapPropProc, (LPARAM)wd)) {
        NHWnd_saveProperty("MapWnd", &wmi->property, sizeof(WINMAPPROP));
        Font_save(&wmi->font, g_propFile, "MapWnd");
        disp_procs.setDispMode(
            wmi->property.draw_type,
            wmi->property.tile_width,
            wmi->property.tile_height);
        NHWnd_newLayout();
        NHWnd_display(wd);
        ShowWindow(wmi->sub_wnd, (wmi->property.show_micro) ? SW_SHOW : SW_HIDE);
    }

    Key_setStatus(keyStat);
}

/*-------------------------------------------------------------------------------------
 *
 *-------------------------------------------------------------------------------------*/
void MapWnd_cmdEffect(WINDESC *wd, int col, int row, int type)
{
    WINMAPINFO *wmi = (WINMAPINFO*)wd->pinfo;
    HDC hdc;

    if(wmi->property.show_tile
        && wmi->property.show_effect && disp_procs.dispEffect) {
        hdc = GetDC(wd->hwnd);
        disp_procs.dispEffect(wd->hwnd, hdc, col, row, type, wmi->property.effect_delay);
        ReleaseDC(wd->hwnd, hdc);
    }
}

/*-------------------------------------------------------------------------------------
 * Map window property dialog procedure
 *-------------------------------------------------------------------------------------*/
static BOOL CALLBACK MapPropProc(HWND hDlg, UINT mesg, UINT wParam, LONG lParam)
{
    static WINMAPPROP  property;
    static WINDESC    *wd;
    static WINMAPINFO *wmi;
    static FONTINFO    font;
    BOOL flg;
    int  idx;

    switch(mesg) {
    case WM_INITDIALOG:

        /* Set initial values */
        wd = (WINDESC *)lParam;
        wmi = (WINMAPINFO *)wd->pinfo;
        CopyMemory(&property, &wmi->property, sizeof(WINMAPPROP));
        CopyMemory(&font, &wmi->font, sizeof(FONTINFO));
        CheckDlgButton(hDlg, property.show_tile ? RADIO_TILE : RADIO_CHAR, BST_CHECKED);
        if(property.draw_type == D_ENTIRE) {
            idx = RADIO_ENTIRE;
            flg = FALSE;
        } else if(property.draw_type == D_DEFAULT) {
            idx = RADIO_DEFAULT;
            flg = FALSE;
        }
        CheckDlgButton(hDlg, idx, BST_CHECKED);
        CheckDlgButton(hDlg, CHECK_EFFECT, property.show_effect ? BST_CHECKED : BST_UNCHECKED);
        EnableWindow(GetDlgItem(hDlg, EDIT_WIDTH), flg);
        EnableWindow(GetDlgItem(hDlg, EDIT_HEIGHT), flg);
        SetDlgItemInt(hDlg, EDIT_WIDTH, property.tile_width, TRUE);
        SetDlgItemInt(hDlg, EDIT_HEIGHT, property.tile_height, TRUE);
        SetDlgItemInt(hDlg, EDIT_DELAY, property.effect_delay, TRUE);
        idx = property.show_micro ? BST_CHECKED : BST_UNCHECKED;
        CheckDlgButton(hDlg, CHECK_MICRO, idx);
        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 BUTTON_FONT:

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

        case IDOK:

            property.show_tile 
                = (IsDlgButtonChecked(hDlg, RADIO_TILE)==BST_CHECKED) ? TRUE : FALSE;
            if(IsDlgButtonChecked(hDlg, RADIO_ENTIRE) == BST_CHECKED) {
                property.draw_type = D_ENTIRE;
            } else if (IsDlgButtonChecked(hDlg, RADIO_DEFAULT) == BST_CHECKED){
                property.draw_type = D_DEFAULT;
                property.tile_width = GetDlgItemInt(hDlg, EDIT_WIDTH, NULL, TRUE);
                property.tile_height = GetDlgItemInt(hDlg, EDIT_HEIGHT, NULL, TRUE);
            }
            property.show_effect = (IsDlgButtonChecked(hDlg, CHECK_EFFECT)==BST_CHECKED)
                ? FLAG_ON : FLAG_OFF;
            property.effect_delay = GetDlgItemInt(hDlg, EDIT_DELAY, NULL, FALSE);
            if(IsDlgButtonChecked(hDlg, CHECK_MICRO) == BST_CHECKED) {
                property.show_micro = FLAG_ON;
            } else {
                property.show_micro = FLAG_OFF;
            }
            CopyMemory(&wmi->property, &property, sizeof(WINMAPPROP));
            CopyMemory(&wmi->font, &font, sizeof(FONTINFO));
            EndDialog(hDlg, 1);
            break;

        case IDCANCEL:

            Font_delete(&font);
            Font_create(&wmi->font);
            EndDialog(hDlg, 0);
            break;

        default:
            return FALSE;
        }
    default:
        return FALSE;
    }

    return TRUE;
}

/***************************************************************************************/
/*
/***************************************************************************************/
void MapWnd_clip(int x, int y)
{
    disp_procs.clip(x, y);
}

/***************************************************************************************/
/* copy map to clipboard
/***************************************************************************************/
void MapWnd_copyText(WINDESC *wd)
{
    WINMAPINFO *wmi;
    int x, y;
    HGLOBAL hglb;
    char *pstr;
   
    if(NHWnd_isValid(wd)) {
        wmi = (WINMAPINFO *)wd->pinfo;
        hglb = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, (COLNO + 2) * ROWNO);
        pstr = GlobalLock(hglb);
        
        for(y = 0; y < ROWNO; y++) {
            for(x = 0; x < COLNO; x++) {
                if(wmi->color[y][x] != INVALID_GLYPH) {
                    pstr[y * (COLNO + 2) + x] = wmi->text[y][x];
                }else { 
                    pstr[y * (COLNO + 2) + x] = ' ';
                }
            }
            pstr[y * (COLNO + 2) + x] = '\r';
            pstr[y * (COLNO + 2) + x + 1] = '\n';
        }
        pstr[y * (COLNO + 1) + x] = '\0';
        GlobalUnlock(hglb);

        OpenClipboard(wd->hwnd);
        EmptyClipboard();
        SetClipboardData(CF_TEXT, hglb);
        CloseClipboard();
    }
}

#endif /* NH2K_EXTENDS */
