//===============================================================
// vselfont.cpp - vSelectFont class functions - Windows
//
// Copyright (C) 1995,1996,1997,1998  Bruce E. Wampler
//
// This file is part of the V C++ GUI Framework, and is covered
// under the terms of the GNU Library General Public License,
// Version 2. This library has NO WARRANTY. See the source file
// vapp.cxx for more complete information about license terms.
//===============================================================
#include <v/vos2.h>		  // for OS/2 stuff
#include <v/vfontsel.h>           // our header
#include <v/vapp.h>
#include <v/vbasewin.h>
//===================>>> vFontSelect::vFontSelect <<<=======================
  vFontSelect::vFontSelect(vBaseWindow* bw, VCONST char* title) // constructor
  {
     _parentHWND = bw->winHwnd();	// track parent's HWND
     _title = title;
     init();
  }
//===================>>> vFontSelect::vFontSelect <<<=======================
  vFontSelect::vFontSelect(vApp* aw, VCONST char* title)
  {
     _parentHWND = aw->winHwnd();	// track parent's HWND
     _title = title;
     init();
  }

//===================>>> vFontSelect::init <<<=======================
  void vFontSelect::init()
  {
    memset(&_fat, 0, sizeof(FATTRS));             // clear structure
    _fat.usRecordLength = sizeof(FATTRS);
    memset(&_fdlg, 0, sizeof(FONTDLG));
    _fdlg.cbSize = sizeof(FONTDLG);
    _fdlg.hpsScreen =  NULLHANDLE;              // Screen presentation space
    _fdlg.hpsPrinter = NULLHANDLE;              // Printer presentation space
    _familyName[0] = '\0';
    _fdlg.pszFamilyname = _familyName;          // Family name of font
    _fdlg.usFamilyBufLen = sizeof(_familyName); // Family name buffer length
    _fdlg.clrFore = CLR_YELLOW;                 // Selected foreground color
    _fdlg.clrBack = CLR_DARKBLUE;               // Selected background color
    _fdlg.fl =   FNTS_INITFROMFATTRS;           // FNTS_* flags dialog styles
    // we set the predefined point sizes to match MS Windows defaults
    _fdlg.pszPtSizeList = "8 9 10 11 12 14 16 18 20 22 24 26 28 36 48 72";
    _fdlg.pszTitle = _title;
  }

//======================>>> vFontSelect::FontSelect <<<=======================
  int vFontSelect::FontSelect(vFont& font, const char* msg)
  {
    // Select a font
    int pointSize = font.GetPointSize();
    _fdlg.fxPointSize = MAKEFIXED(pointSize, 0);    // preselect preview size


    // Set to values of the existing supplied font
    vFontID vfam = font.GetFamily();
    vFontID vstyle = font.GetStyle();
    vFontID vweight = font.GetWeight();
    int isFromFntDlg = font.GetIsFromFntDlg();

    if (font.GetUnderlined())
      _fat.fsSelection = FATTR_SEL_UNDERSCORE;

    // we need to build up the _fat structure so that the font
    // dialog will preload the correct font.  One easy way is to copy
    // over the _fat from the existing font.  This won't always work
    // though because the _fat is only built when the font is used.  A
    // font that is only instantiated will not have its _fat built
    // and the dialog will not preload properly.
    switch (vfam)
    {
      case vfOtherFont:   // non-standard V font
        // pretty much the only way to select vfOtherFont is by way of the
        // font dialog, but we will check anyway
        if (isFromFntDlg)
         memcpy(&_fat, font.GetPFAT(), sizeof(FATTRS));
        // we trap the case where vfOtherfont was specified
        // other than by a font dialog selection (should not happen)
        else
        {
          _fat.fsFontUse = 0;
          strncpy(_fat.szFacename, "System Proportional",FACESIZE);
          LoadFat(vfam, vstyle, vweight, isFromFntDlg, pointSize);
        }
        break;

      case vfSerif:	// Serif font
        _fat.fsFontUse = FATTR_FONTUSE_OUTLINE;
        if (vweight == vfNormal && vstyle == vfNormal)
          strncpy(_fat.szFacename, "Times New Roman", FACESIZE);
        else if (vweight == vfBold && vstyle == vfNormal)
          strncpy(_fat.szFacename, "Times New Roman Bold", FACESIZE);
        else if (vweight == vfNormal && vstyle == vfItalic)
          strncpy(_fat.szFacename, "Times New Roman Italic", FACESIZE);
        else
          strncpy(_fat.szFacename, "Times New Roman Bold Italic", FACESIZE);
        LoadFat(vfam, vstyle, vweight, isFromFntDlg, pointSize);
        break;

      case vfSansSerif:	// SansSerif Font
	_fat.fsFontUse = FATTR_FONTUSE_OUTLINE;
	if (vweight == vfNormal && vstyle == vfNormal)
	  strncpy(_fat.szFacename, "Helvetica", FACESIZE);
	else if (vweight == vfBold && vstyle == vfNormal)
	  strncpy(_fat.szFacename, "Helvetica Bold", FACESIZE);
	else if (vweight == vfNormal && vstyle == vfItalic)
	  strncpy(_fat.szFacename, "Helvetica Italic", FACESIZE);
	else
	  strncpy(_fat.szFacename, "Helvetica Bold Italic", FACESIZE);
        LoadFat(vfam, vstyle, vweight, isFromFntDlg, pointSize);
	break;

      case vfFixed:		// Fixed
        _fat.fsFontUse = FATTR_FONTUSE_OUTLINE;
        if (vweight == vfNormal && vstyle == vfNormal)
          strncpy(_fat.szFacename, "Courier", FACESIZE);
        else if (vweight == vfBold && vstyle == vfNormal)
          strncpy(_fat.szFacename, "Courier Bold", FACESIZE);
        else if (vweight == vfNormal && vstyle == vfItalic)
          strncpy(_fat.szFacename, "Courier Italic", FACESIZE);
        else
          strncpy(_fat.szFacename, "Courier Bold Italic", FACESIZE);
        LoadFat(vfam, vstyle, vweight, isFromFntDlg, pointSize);
        break;

      case vfDecorative:       // Decorative
        _fat.fsFontUse = FATTR_FONTUSE_OUTLINE;
        strncpy(_fat.szFacename, "Symbol Set", FACESIZE);
        _fat.usCodePage = 65400;
        LoadFat(vfam, vstyle, vweight, isFromFntDlg, pointSize);
        break;

      case vfDefaultVariable:  // default font
        _fat.fsFontUse = 0;
        strncpy(_fat.szFacename, "System Proportional",FACESIZE);
        LoadFat(vfam, vstyle, vweight, isFromFntDlg, pointSize);
        break;

      case vfDefaultSystem:
      case vfDefaultFixed:     // default font
      default:
        _fat.fsFontUse = 0;
        strncpy(_fat.szFacename, "System Monospaced",FACESIZE);
        LoadFat(vfam, vstyle, vweight, isFromFntDlg, pointSize);
        break;
    }

    // copy the fat for the existing font to the font dialog structure
    // so we can have the correct font preselected in the font dialog
    memcpy(&_fdlg.fAttrs, &_fat, sizeof(FATTRS));   // preselect font

    WinFontDlg (HWND_DESKTOP, _parentHWND, &_fdlg);

    if (_fdlg.lReturn == DID_OK)
    {
      font.SetWinFontValues(_fdlg);
      return 1;
    }
    else
      return 0;
  }


//=======================>>> vFont::LoadFat <<<=============================
  void vFontSelect::LoadFat(vFontID vfam, vFontID vstyle, vFontID vweight,
    int isFromFntDlg, int pointSize)
  {

    // fill in the _fat structure
    ULONG chrSet = theApp->AppCP();
    switch (vfam)
    {
      // make monospaced system default as per windows code
      case vfDefaultSystem:
      case vfDefaultFixed:
        _fat.fsFontUse = 0;
        strncpy(_fat.szFacename, "System Monospaced", FACESIZE);
        break;

      case vfSerif:	// Serif font
        _fat.fsFontUse = FATTR_FONTUSE_OUTLINE;
        if (vweight == vfNormal && vstyle == vfNormal)
          strncpy(_fat.szFacename, "Times New Roman", FACESIZE);
        else if (vweight == vfBold && vstyle == vfNormal)
          strncpy(_fat.szFacename, "Times New Roman Bold", FACESIZE);
        else if (vweight == vfNormal && vstyle == vfItalic)
          strncpy(_fat.szFacename, "Times New Roman Italic", FACESIZE);
        else
          strncpy(_fat.szFacename, "Times New Roman Bold Italic", FACESIZE);
        break;

      case vfSansSerif:	// SansSerif Font
        _fat.fsFontUse = FATTR_FONTUSE_OUTLINE;
        if (vweight == vfNormal && vstyle == vfNormal)
          strncpy(_fat.szFacename, "Helvetica", FACESIZE);
        else if (vweight == vfBold && vstyle == vfNormal)
          strncpy(_fat.szFacename, "Helvetica Bold", FACESIZE);
        else if (vweight == vfNormal && vstyle == vfItalic)
          strncpy(_fat.szFacename, "Helvetica Italic", FACESIZE);
        else
          strncpy(_fat.szFacename, "Helvetica Bold Italic", FACESIZE);
        break;

      case vfFixed:		// Courier font
        _fat.fsFontUse = FATTR_FONTUSE_OUTLINE;
        if (vweight == vfNormal && vstyle == vfNormal)
          strncpy(_fat.szFacename, "Courier", FACESIZE);
        else if (vweight == vfBold && vstyle == vfNormal)
          strncpy(_fat.szFacename, "Courier Bold", FACESIZE);
        else if (vweight == vfNormal && vstyle == vfItalic)
          strncpy(_fat.szFacename, "Courier Italic", FACESIZE);
        else
          strncpy(_fat.szFacename, "Courier Bold Italic", FACESIZE);
        break;

      case vfDecorative:	// Decorative
        _fat.fsFontUse = FATTR_FONTUSE_OUTLINE;
        strncpy(_fat.szFacename, "Symbol Set", FACESIZE);
        chrSet = 65400;
        break;

      case vfOtherFont:	// set by font picker dialog
          break;

      case vfDefaultVariable:	// default font
      default:
        _fat.fsFontUse = 0;
        strncpy(_fat.szFacename, "System Proportional",FACESIZE);
        break;
    }
    // Now, set the rest of the font attributes
    _fat.usCodePage = chrSet;

    // synthesize attributes if bitmap font
    if (!(_fat.fsFontUse & FATTR_FONTUSE_OUTLINE))
    {
      if (vweight == vfNormal && vstyle == vfItalic)
	_fat.fsSelection = FATTR_SEL_ITALIC;
      else if (vweight == vfBold && vstyle == vfNormal)
	_fat.fsSelection = FATTR_SEL_BOLD;
      else if (vweight == vfBold && vstyle == vfItalic)
	_fat.fsSelection = FATTR_SEL_BOLD | FATTR_SEL_ITALIC;

      // compute required pointsize if not from font dialog box
      if (isFromFntDlg == 0 )
      {
	// For bitmap (image) fonts we match the requested font point size
        // to the os/2 font with the closest font size for the system dpi!
        // But there's more to this nightmare.  We must query the bitmap font
        // FONTMETRICS to get the exact value for MaxBaseLineExt and AveCharWidth.
        // in order to select the font, otherwise the selection fails
        // and we get the default font which is System Proportional!!!!!
	// They must have been on heavy drugs when they came
	// with this bizarre font API
        LoadBitmapFont(pointSize);
      }
    }
  }


//====================>>> vFont::loadBitmapFont <<<==========================
  // finds the nearest bitmap font to the requested pointsize and
  // facename.  This is for internal use only. Minimal error
  // checking is done.
  void vFontSelect::LoadBitmapFont(int pointSize)
  {
    PFONTMETRICS pFM, pCurFM;
    LONG Count = 0L;
    int  i;

    // Do any fonts with the requested facename exist
    HPS dc = WinGetScreenPS (HWND_DESKTOP);
    Count = GpiQueryFonts (dc, QF_PUBLIC | QF_PRIVATE, _fat.szFacename,
      &Count, (LONG)sizeof(FONTMETRICS), 0);

    if (Count)
    {
      // If so allocate memory and retrieve their metrics
      DosAllocMem ((PPVOID)&pFM, sizeof(FONTMETRICS) * (USHORT)Count,
        OBJ_TILE | PAG_READ | PAG_WRITE | PAG_COMMIT);

      GpiQueryFonts (dc,QF_PUBLIC | QF_PRIVATE, _fat.szFacename,
        &Count, (LONG)sizeof(FONTMETRICS), pFM);

      // get the font resolution (dpi) of the display
      HDC hDevCxt = GpiQueryDevice(dc);
      LONG   cxFontRes, cyFontRes;
      DevQueryCaps(hDevCxt, CAPS_VERTICAL_FONT_RES, 1L, &cyFontRes);
      DevQueryCaps(hDevCxt, CAPS_HORIZONTAL_FONT_RES, 1L, &cxFontRes);

      // Look through the list trying to find a match
      pCurFM = pFM;
      int BestDelta = 9999999;   // set to something huge

      while (Count)
      {
        if (pCurFM->fsDefn & FM_DEFN_OUTLINE)
        {
          // this should not happen, since this is intended to be used
          // only for finding bitmap fonts
          continue;
        }
        // check if resolution is what we are looking for +/- some slop
        else if ( (pCurFM->sYDeviceRes == cyFontRes) &&
          (pCurFM->sXDeviceRes == cxFontRes) )
        {
          int Delta = abs((pCurFM->sNominalPointSize / 10) - pointSize);
          if (Delta <= BestDelta)
          {
            BestDelta = Delta;
            pFM = pCurFM;
          }
        }
        Count--;
        if (Count)
          pCurFM++;

        // now set the font attributes to those of the best match
        _fat.lAveCharWidth = pFM->lAveCharWidth;
        _fat.lMaxBaselineExt = pFM->lMaxBaselineExt;

        SysDebug3(Text,"vFontSelect::LoadBitmapFont CharWidth=%u BaseLineExt=%u (Delta=%u)\n",
          pFM->lAveCharWidth, pFM->lMaxBaselineExt, BestDelta);
        SysDebug2(OS2Dev,"          _fat = %u this=%x \n", &_fat, this)
      }
      DosFreeMem(pFM);
    }
  }

// ---------------------------------------------------------------------


