#define INCL_DOSERRORS
#define INCL_GPI
#define INCL_WIN

#include "vxrexx.h"
#include "vxfuncs.h"

#include <bseerr.h>

#include "tipwin.h"

LONG GetCurrentDPI( HWND hwnd );
BOOL GetImageFont( HPS hps, PSZ pszFont, LONG lPts, LONG lDPI, PFATTRS pfAttrs );
BOOL SetFontFromPP( HPS hps, HWND hwnd, LONG lDPI );
void UpdateSize( HWND hwnd, PSZ pszText );


/* ------------------------------------------------------------------------- *
 * Window procedure for the TT_Popup control.                                *
 * ------------------------------------------------------------------------- */
MRESULT EXPENTRY TTPopupProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
{
    PTTCTLDATA    pData = NULL;         // pointer to control instance data
    PCREATESTRUCT pCreate;              // pointer to WM_CREATE data
    PWNDPARAMS    pWP;                  // pointer to window parameters
    HPS           hps;                  // control's presentation space
    RECTL         rcl;                  // control's window area
    POINTL        ptl;                  // current drawing position
    POINTS        pts;                  // current pointer position
    LONG          clrBG, clrFG;         // current fore/back colours
    PSZ           pszText = NULL;
    ULONG         cbText,
                  ulid,
                  rc;
//FILE *f;


    switch( msg ) {

        case WM_CREATE:
            //pCreate = (PCREATESTRUCT) mp2;
            pData = (PTTCTLDATA) VRMemAlloc( sizeof( TTCTLDATA ));
            pData->cb = sizeof( TTCTLDATA );
            pData->fs = 0;
            pData->pszCaption = NULL;
            WinSetWindowPtr( hwnd, 0, pData );
            return (MRESULT) FALSE;


        case WM_DESTROY:
            pData = WinQueryWindowPtr( hwnd, 0 );
            if ( pData ) {
                if ( pData->pszCaption ) free( pData->pszCaption );
                free( pData );
            }
            break;


        case WM_PAINT:
            hps = WinBeginPaint( hwnd, NULLHANDLE, NULLHANDLE );

            // get the current colours
            GpiCreateLogColorTable( hps, LCOL_RESET, LCOLF_RGB, 0, 0, NULL );
            rc = WinQueryPresParam( hwnd, PP_FOREGROUNDCOLOR, PP_FOREGROUNDCOLORINDEX,
                                    &ulid, sizeof(clrFG), &clrFG, QPF_ID2COLORINDEX );
            if ( !rc )
            clrFG = SYSCLR_WINDOWTEXT;

            rc = WinQueryPresParam( hwnd, PP_BACKGROUNDCOLOR, PP_BACKGROUNDCOLORINDEX,
                                    &ulid, sizeof(clrBG), &clrBG, QPF_ID2COLORINDEX );
            if ( !rc )
            clrBG = SYSCLR_WINDOW;

            // paint the border & background
            WinQueryWindowRect( hwnd, &rcl );
            WinFillRect( hps, &rcl, clrBG );

            ptl.x = 0; ptl.y = 0;
            GpiMove( hps, &ptl );
            ptl.x = rcl.xRight - 1; ptl.y = rcl.yTop - 1;
            GpiSetColor( hps, clrFG );
            GpiBox( hps, DRO_OUTLINE, &ptl, 0, 0 );

            // paint the text
            SetFontFromPP( hps, hwnd, GetCurrentDPI( hwnd ));
            pData = WinQueryWindowPtr( hwnd, 0 );
            if ( pData && pData->pszCaption ) {
                ptl.x = ( rcl.xRight - rcl.xLeft ) / 2;
                ptl.y = ( rcl.yTop - rcl.yBottom ) / 2;
                cbText = strlen( pData->pszCaption );
                WinDrawText( hps, cbText, pData->pszCaption, &rcl, clrFG, clrBG,
                             DT_CENTER | DT_VCENTER | DT_WORDBREAK );
            }

            // done
            WinEndPaint( hps );
            return (MRESULT) 0;


        case WM_PRESPARAMCHANGED:
            pData = WinQueryWindowPtr( hwnd, 0 );
            switch ( (ULONG) mp1 ) {
                case PP_FONTNAMESIZE:
                    // recalculate required window size
                    if ( pData ) UpdateSize( hwnd, pData->pszCaption );
                case PP_BACKGROUNDCOLOR:
                case PP_BACKGROUNDCOLORINDEX:
                case PP_FOREGROUNDCOLOR:
                case PP_FOREGROUNDCOLORINDEX:
                    WinInvalidateRect( hwnd, NULL, FALSE );
                    break;
                default: break;
            }
            break;


        case WM_SETWINDOWPARAMS:
            pData = WinQueryWindowPtr( hwnd, 0 );
            pWP = (PWNDPARAMS) mp1;
            if ( pData && pWP && ( pWP->fsStatus & WPM_TEXT )) {
                if ( pData->pszCaption ) VRMemFree( pData->pszCaption );
                if ( !pWP->cchText || !pWP->pszText ) {
                    pData->pszCaption = NULL;
                }
                else {
                    pData->pszCaption = (PSZ) VRMemAlloc( pWP->cchText + 1 );
                    if ( pData->pszCaption ) {
                        strncpy( pData->pszCaption, pWP->pszText, pWP->cchText );
                        pData->pszCaption[ pWP->cchText ] = '\0';
                    }
                    else return (MRESULT) FALSE;
                }
                UpdateSize( hwnd, pData->pszCaption );
                WinInvalidateRect( hwnd, NULL, FALSE );
                return (MRESULT) TRUE;
            }
            break;

    }

    return ( WinDefWindowProc( hwnd, msg, mp1, mp2 ));
}


/* ------------------------------------------------------------------------- *
 * GetCurrentDPI                                                             *
 *                                                                           *
 * Queries the current vertical font resolution (a.k.a. DPI).                *
 *                                                                           *
 * ARGUMENTS:                                                                *
 *   HWND hwnd: Window handle of control.                                    *
 *                                                                           *
 * RETURNS: LONG                                                             *
 *   Current screen DPI setting.                                             *
 * ------------------------------------------------------------------------- */
LONG GetCurrentDPI( HWND hwnd )
{
    HDC  hdc;           // device-context handle
    LONG lCap,          // value from DevQueryCaps
         lDPI;          // returned DPI value

    hdc = WinOpenWindowDC( hwnd );
    if ( DevQueryCaps( hdc, CAPS_VERTICAL_FONT_RES, 1, &lCap ))
        lDPI = lCap;
    if ( !lDPI )
        lDPI = 96;

    return lDPI;
}


/* ------------------------------------------------------------------------- *
 * GetImageFont                                                              *
 *                                                                           *
 * Look for a bitmap (a.k.a. image or raster) font under the specified font  *
 * name.  This is necessary because PM sees every distinct point size of a   *
 * bitmap font as a separate font (albeit with a shared family name).        *
 *                                                                           *
 * This function specifically looks for bitmap rather than outline (vector)  *
 * fonts; if no bitmap versions of the requested font name are found, we     *
 * return FALSE.  (The caller will presumably try to treat pszFontFace as an *
 * outline font in such a case; whether it wants to verify its existence or  *
 * not before doing so is its own problem.)                                  *
 *                                                                           *
 * If an exact match is found, the font attributes structure will be         *
 * populated with the appropriate font information, and the function will    *
 * return TRUE.  Otherwise, FALSE will be returned (and the contents of      *
 * pfAttrs will not be altered).                                             *
 *                                                                           *
 * ARGUMENTS:                                                                *
 *   HPS     hps    : Handle of the current presentation space.         (I)  *
 *   PSZ     pszFont: Face name of the font being requested.            (I)  *
 *   LONG    lPts   : The requested point size (multiple of 10).        (I)  *
 *   LONG    lDPI   : The requested device resolution (DPI).            (I)  *
 *   PFATTRS pfAttrs: Pointer to font attributes structure.             (IO) *
 *                                                                           *
 * RETURNS: BOOL                                                             *
 *   TRUE if a suitable bitmap font was found; FALSE otherwise.              *
 * ------------------------------------------------------------------------- */
BOOL GetImageFont( HPS hps, PSZ pszFont, LONG lPts, LONG lDPI, PFATTRS pfAttrs )
{
    PFONTMETRICS pfm;               // array of FONTMETRICS objects
    LONG         i,                 // loop index
                 cFonts    = 0,     // number of fonts found
                 cCount    = 0;     // number of fonts to return
    BOOL         fFound    = FALSE; // did we find a suitable bitmap font?


    // Find the specific fonts which match the given face name
    cFonts = GpiQueryFonts( hps, QF_PUBLIC, pszFont, &cCount, 0, NULL );
    if ( cFonts < 1 ) return FALSE;
    if ( DosAllocMem( (PPVOID) &pfm, ( cFonts * sizeof( FONTMETRICS )),
                        PAG_COMMIT | PAG_READ | PAG_WRITE ) != NO_ERROR )
        return FALSE;
    GpiQueryFonts( hps, QF_PUBLIC, pszFont,
                   &cFonts, sizeof( FONTMETRICS ), pfm );

    // Look for a bitmap font that matches the requested size and resolution
    for ( i = 0; ( i < cFonts) && !fFound; i++ ) {
        if ( pfm[i].fsDefn & FM_DEFN_OUTLINE ) continue;

        if (( pfm[i].sNominalPointSize == lPts ) &&
            ( pfm[i].sYDeviceRes == lDPI ))
        {
            strcpy( pfAttrs->szFacename, pfm[i].szFacename );
            pfAttrs->lMatch          = pfm[i].lMatch;
            pfAttrs->idRegistry      = pfm[i].idRegistry;
            pfAttrs->lMaxBaselineExt = pfm[i].lMaxBaselineExt;
            pfAttrs->lAveCharWidth   = pfm[i].lAveCharWidth;
            pfAttrs->fsType          = pfm[i].fsType;
            fFound = TRUE;
            break;
        }
    }

    DosFreeMem( pfm );
    return ( fFound );
}


/* ------------------------------------------------------------------------- *
 * SetFontFromPP                                                             *
 *                                                                           *
 * Sets the active GPI font from the current font presentation parameter.    *
 * It will always be assigned a logical font ID of 1.                        *
 *                                                                           *
 * ARGUMENTS:                                                                *
 *   HPS  hps : Current presentation space handle.                           *
 *   HWND hwnd: Window handle of control.                                    *
 *   LONG lDPI: Current screen DPI setting.                                  *
 *                                                                           *
 * RETURNS: BOOL                                                             *
 *   TRUE on success, FALSE on error.                                        *
 * ------------------------------------------------------------------------- */
BOOL SetFontFromPP( HPS hps, HWND hwnd, LONG lDPI )
{
    FATTRS  fa = {0};                     // required font attributes
    SIZEF   sfCell;                       // character cell size
    CHAR    szFont[ FACESIZE+5 ] = {0};   // current font pres.param
    PSZ     pszFontName;                  // requested font family
    ULONG   ulPts;                        // requested font size
    APIRET  rc;

    // Get the font name from the presentation parameter
    rc = WinQueryPresParam( hwnd, PP_FONTNAMESIZE,
                            0L, NULL, sizeof( szFont ), szFont, 0L );
    if ( !rc )
        return FALSE;

    // Define the requested font attributes
    fa.usRecordLength = sizeof( FATTRS );
    fa.fsType         = FATTR_TYPE_MBCS;
    fa.fsFontUse      = FATTR_FONTUSE_NOMIX;
    pszFontName = strchr( szFont, '.') + 1;
    strcpy( fa.szFacename, pszFontName );
    if ( sscanf( szFont, "%d.", &ulPts ) != 1 )
        ulPts = 10;

    // If this is a bitmap font, look up the proper name+size
    if ( ! GetImageFont( hps, pszFontName, (LONG)(ulPts*10), lDPI, &fa ))
    {
        /* No bitmap font found.  Assume it's an outline font and scale it to
         * the requested point size according to the current DPI setting.
         */
        double dScale = ( (double) lDPI / 72 );
        ulPts = ulPts * dScale;
        sfCell.cy = MAKEFIXED( ulPts, 0 );
        sfCell.cx = sfCell.cy;
        GpiSetCharBox( hps, &sfCell );
    }

    // Make the font active
    if ( GpiCreateLogFont( hps, NULL, 1L, &fa ) == GPI_ERROR )
        return FALSE;
    if ( GpiSetCharSet( hps, 1L ) == GPI_ERROR )
        return FALSE;

    return TRUE;
}



/* ------------------------------------------------------------------------- *
 * UpdateSize                                                                *
 *                                                                           *
 * Updates the window size to match the current font & text.                 *
 *                                                                           *
 * ARGUMENTS:                                                                *
 *   HWND hwnd   : Window handle of control.                                 *
 *   PSZ  pszText: Current caption text                                      *
 *                                                                           *
 * RETURNS: N/A                                                              *
 * ------------------------------------------------------------------------- */
void UpdateSize( HWND hwnd, PSZ pszText )
{
    HPS  hps;
    LONG lHeight, lWidth;

    if ( !pszText ) return;

    hps = WinGetPS( hwnd );
    SetFontFromPP( hps, hwnd, GetCurrentDPI( hwnd ));
    if ( ! VRGetTextExtent( hwnd, hps, pszText, &lHeight, &lWidth, TRUE )) {
        lHeight = 20;
        lWidth  = 20;
    }
    WinSetWindowPos( hwnd, 0L, 0, 0, lWidth, lHeight, SWP_SIZE );
    WinReleasePS( hps );

}
