/* $Header$ */
/*
FONTOPS non-visual component
Changes
Date			Edit				Bug					Description
10-Oct-22	rmm11757		ST/FU/838		Problem with FontOps.$wintextwidth().
02-Mar-22	rmm11466								Implemented new build numbering and serial numbers to support Studio Now releases and periodic releases.
13-Jun-16	rmm8939			ST/FU/670		Code assistant now restricts constants to the set suitable for function and external component object method parameters.
30-Jan-14	rmm8235			ST/FU/636		Problem listing fonts.
18-Jun-13	rmm8013									Updated Omnis X dictionary and added new JNI API to return dictionary as XML.
19-Mar-13	rmm64bit6								Changes required for compiling with 64 bit target.
31-Jul-09	rmm6695			ST/FU/572		Remove validation of zero point size, as zero is now valid (GDI uses a sensible default in this case).
29-Mar-07	rmm6029									$designdpi modified to have per-platform support.
18-Mar-03 MHn0209			ST/FU/364		Fixed fontheight for OSX Theme Fonts.
16-Apr-99	rmm3418									Fixed memory leak.
26-May-98	rmm3101									Added $winlistfonts and $replistfonts to FontOps NVC.
21-May-98	rmm3094									New File
*/

#include <extcomp.he>
#include <extfval.he>
#include <hwnd.he>
#include <gdi.he>
#include "fontops.he"
#include "dmconst.he"	// rmm8939

#define VERSION_MAJOR			1				// Major Version number - Update on MAJOR release builds  
#define VERSION_MINOR			0				// Minor Version number - Update on release builds

// Start rmm8013: Static function parameter definitions added here; also updated fontopsStaticFuncs array
// $wintextwidth(string,font-name|font-table-index,point-size[,font-style])
// $reptextwidth(string,font-name|font-table-index,point-size[,font-style])
static ECOparam FONTOPStextWidthParams[] =
{
	7000, fftCharacter,	0, 0,
	7001, fftCharacter,	0, 0,
	7002, fftInteger,	0, 0,
	7003, fftInteger, EXTD_FLAG_PARAMOPT, EXT_BUILTIN | MAKELONG(preFontstyleF, preFontstyleL)	// rmm8939
};
#define FONTOPStextWidthParamsCount (sizeof(FONTOPStextWidthParams)/sizeof(FONTOPStextWidthParams[0]))

// $wintextheight(font-name|font-table-index,point-size[,font-style,extra-points])
// $reptextheight(font-name|font-table-index,point-size[,font-style,extra-points])
static ECOparam FONTOPStextHeightParams[] =
{
	7001, fftCharacter,	0, 0,
	7002, fftInteger,	0, 0,
	7003, fftInteger, EXTD_FLAG_PARAMOPT, EXT_BUILTIN | MAKELONG(preFontstyleF, preFontstyleL),	// rmm8939
	7004, fftInteger, EXTD_FLAG_PARAMOPT, 0,
};
#define FONTOPStextHeightParamsCount (sizeof(FONTOPStextHeightParams)/sizeof(FONTOPStextHeightParams[0]))

// $winlistfonts(list)
// $replistfonts(list)
static ECOparam FONTOPSlistParams[] =
{
	7005, fftList,		EXTD_FLAG_PARAMALTER, 0,
};
#define FONTOPSlistParamsCount (sizeof(FONTOPSlistParams)/sizeof(FONTOPSlistParams[0]))
// End rmm8013

////////////////////////////
ECOmethodEvent fontopsStaticFuncs[ cSMethod_Count ] = 
{
	cSMethodId_WinTextWidth				, 8000,	fftInteger,	FONTOPStextWidthParamsCount, FONTOPStextWidthParams, 0, 0,
	cSMethodId_RepTextWidth 			,	8001,	fftInteger,	FONTOPStextWidthParamsCount, FONTOPStextWidthParams, 0, 0,
	cSMethodId_WinTextHeight 			,	8002,	fftInteger, FONTOPStextHeightParamsCount, FONTOPStextHeightParams, 0, 0,
	cSMethodId_RepTextHeight 			,	8003,	fftInteger, FONTOPStextHeightParamsCount, FONTOPStextHeightParams, 0, 0,
	cSMethodId_WinListFonts 			,	8004,	fftInteger,	FONTOPSlistParamsCount, FONTOPSlistParams, 0, 0, // rmm3101
	cSMethodId_RepListFonts 			,	8005,	fftInteger,	FONTOPSlistParamsCount, FONTOPSlistParams, 0, 0, // rmm3101
};

#define MAX_PARAMS 	 6
qbool tqfFontOpsObj::staticMethod(EXTCompInfo *pEci)
{
	qlong funcId = ECOgetId(pEci);
	EXTParamInfo *param[MAX_PARAMS];
	for (qshort n = 1; n <= MAX_PARAMS; n++)
	{
		param[n-1] = ECOfindParamNum(pEci, n);
	}
	qshort paramCount = ECOgetParamCount(pEci); 
	qbool methodFound = qtrue;
	qlong resultVal = 0;
	qreal realResultVal;
	qbool isReal = qfalse;
	switch (funcId)
	{
		case cSMethodId_WinTextWidth:
			resultVal = winTextWidth(paramCount, param, pEci);
			break;
		case cSMethodId_RepTextWidth:
			realResultVal = repTextWidth(paramCount, param, pEci);
			isReal = qtrue;
			break;
		case cSMethodId_WinTextHeight:
			resultVal = winTextHeight(paramCount, param, pEci);
			break;
		case cSMethodId_RepTextHeight:
			realResultVal = repTextHeight(paramCount, param, pEci);
			isReal = qtrue;
			break;
		case cSMethodId_WinListFonts: // rmm3101
			resultVal = listFonts(qfalse, paramCount, param, pEci);
			break;
		case cSMethodId_RepListFonts: // rmm3101
			resultVal = listFonts(qtrue, paramCount, param, pEci);
			break;
		default:
			methodFound = qfalse;
			break;
	}
	if (methodFound)
	{ // Push error code
		EXTfldval result;
		if (isReal) result.setNum(realResultVal); else result.setLong(resultVal);
    ECOaddParam(pEci, &result);
	}
	return methodFound;
}

// $wintextwidth(String,{Font-table-index|Font-name},Point-size[,Text-style])
qlong tqfFontOpsObj::winTextWidth(qshort pParamCount, EXTParamInfo **pParams, EXTCompInfo *pEci)
{
	if (pParamCount < 3 || pParamCount > 4) return kFontOpsParamError;

	GDItextSpecStruct ts;
	qlong status = getFont(ts, pEci->mLocLocp, qfalse, pParams[1], pParams[2], pParams[3]);
	if (status < 0) return status;

	EXTfldval fvalString((qfldval) pParams[0]->mData);
	qHandle 	han = fvalString.getHandle(qfalse);
	qHandleTextPtr	hp(han, 0);
	if (!hp.charLen()) return 0;
	return scaleValueToDesign(GDItextWidth(&hp[0], (qshort) hp.charLen(), &ts), pEci); // rmm6029
}

// $wintextheight({Font-table-index|Font-name},Point-size[,Text-style,Extra-points])
qlong tqfFontOpsObj::winTextHeight(qshort pParamCount, EXTParamInfo **pParams, EXTCompInfo *pEci)
{
	if (pParamCount < 2 || pParamCount > 4) return kFontOpsParamError;

	GDItextSpecStruct ts;
	qlong status = getFont(ts, pEci->mLocLocp, qfalse, pParams[0], pParams[1], pParams[2], pParams[3]);
	if (status < 0) return status;

	HFONT theFont = GDIcreateFont(&ts.mFnt, ts.mSty);
	HDC hdc = GDIgetTempDC();
	HFONT oldFont = GDIselectObject(hdc, theFont);
	qlong height = GDIfontHeight(hdc, ts.mFnt.extra());
	GDIselectObject(hdc, oldFont);
	GDIdeleteObject(theFont);
	return scaleValueToDesign(height, pEci);	// rmm6029
}

// $reptextwidth(String,{Font-table-index|Font-name},Point-size[,Text-style])
qreal tqfFontOpsObj::repTextWidth(qshort pParamCount, EXTParamInfo **pParams, EXTCompInfo *pEci)
{
	if (pParamCount < 3 || pParamCount > 4) return kFontOpsParamError;

	GDItextSpecStruct ts;
	qlong status = getFont(ts, pEci->mLocLocp, qtrue, pParams[1], pParams[2], pParams[3]);
	if (status < 0) return status;

	EXTfldval fvalString((qfldval) pParams[0]->mData);
	qHandle 	han = fvalString.getHandle(qfalse);
	qHandleTextPtr	hp(han, 0);
	if (!hp.charLen()) return 0;

	if (PRI_ERR_NONE != PRIopen()) return kFontOpsPrintManagerError;
	qpridim width = PRItextWidth(0, &hp[0], hp.charLen(), &ts);
	qreal cmOrInch;
	PRIconvToCMorINCH(width, cmOrInch);
	PRIclose();
	return cmOrInch;
}

// $reptextheight({Font-table-index|Font-name},Point-size[,Text-style,Extra-points])
qreal tqfFontOpsObj::repTextHeight(qshort pParamCount, EXTParamInfo **pParams, EXTCompInfo *pEci)
{
	if (pParamCount < 2 || pParamCount > 4) return kFontOpsParamError;

	GDItextSpecStruct ts;
	qlong status = getFont(ts, pEci->mLocLocp, qtrue, pParams[0], pParams[1], pParams[2], pParams[3]);
	if (status < 0) return status;

	if (PRI_ERR_NONE != PRIopen()) return kFontOpsPrintManagerError;
	qpridim height = PRItextHeight(0, &ts.mFnt);
	qreal cmOrInch;
	PRIconvToCMorINCH(height, cmOrInch);
	PRIclose();
	return cmOrInch;
}

// Get the qfnt for the specified font
qlong	tqfFontOpsObj::getFont(GDItextSpecStruct &pTs, locptype *pLocp, qbool pIsRep, 
														 EXTParamInfo *pFontParam, EXTParamInfo *pPointSizeParam, 
														 EXTParamInfo *pTextStyleParam, EXTParamInfo *pExtraPointsParam)
{
	// Get point size first
	EXTfldval fvalSize((qfldval) pPointSizeParam->mData);
	qshort size = (qshort) fvalSize.getLong();

	// Next, font table index or font name
	EXTfldval fvalFont((qfldval) pFontParam->mData);
	qshort index = (qshort) fvalFont.getLong();
	if (index < 1 || index > 16) 
	{
		// Not a valid font index.  Try a font name
		str255 fontName;
		str15 lthemetxt; // MHn0209
		RESloadString(gInstLib,5000,lthemetxt); // MHn0209
		fvalFont.getChar(fontName);
		// MHn0209 begins
		// Allow size of 0 to be specified for Theme Fonts.
		if (fontName.pos(lthemetxt)==0) 
		{
			if (size < 0) return kFontOpsInvalidPointSize;  // rmm6695
		}
		// MHn0209 ends

		qlong num;
		if (stringToQlong(fontName, num)) return kFontOpsInvalidFontIndex; // If its a number, assume its not a font name

		GDIsetFontName(&pTs.mFnt, &fontName[1], fontName.length());
		GDIfontSetSize(&pTs.mFnt, size);
	}
	else
	{
		if (size < 0) return kFontOpsInvalidPointSize; // MHn0209 // rmm6695
		qapp app = ECOgetApp(pLocp);
		ECOgetFont(app, pIsRep, &pTs.mFnt, index, size);
		#if defined(iswin32) || defined(iswin16)
			if (pIsRep) // rmm11757
			{
				// For reports remove charset and family, as we do not use them any more for reports
				pTs.mFnt.charset(0);
				pTs.mFnt.family(0);
			}
		#endif
	}

	// Text style
	if (pTextStyleParam)
	{
		EXTfldval fvalStyle((qfldval) pTextStyleParam->mData);
		pTs.mSty = (qsty) fvalStyle.getLong();
	}
	else pTs.mSty = styPlain;

	// Extra spacing
	if (pExtraPointsParam)
	{
		EXTfldval fvalExtra((qfldval) pExtraPointsParam->mData);
		qint1 extra = (qint1) fvalExtra.getLong();
		if (extra < 0 || extra > 72) return kFontOpsInvalidExtraPoints;
		pTs.mFnt.extra(extra);
	}

	// Success
	pTs.mJst = jstLeft;
	pTs.mTextColor = colDefault;
	return 0;
}

// rmm6029: added this method - any values returned for window fonts need to be scaled to design DPI, since design DPI values
// are required for $height etc.
qlong tqfFontOpsObj::scaleValueToDesign(qlong pValue, EXTCompInfo *pEci)
{
	GDIscaleValueStruct svs;
	svs.mApp = ECOgetApp(pEci->mLocLocp);
	svs.mValue = (qshort) pValue;
	return (qlong) WNDsendMessage(0, WM_CONTROL, SCALE_VALUE_TO_DESIGN, (LPARAM) &svs); // rmm64bit6
}

// rmm3101
qlong tqfFontOpsObj::listFonts(qbool pIsRep, qshort pParamCount, EXTParamInfo **pParams, EXTCompInfo *pEci)
{
	if (pParamCount != 1) return kFontOpsParamError;

	// Get the first parameter, and make sure its a list
	EXTfldval fvalList((qfldval) pParams[0]->mData);
	// Start rmm8235
	ffttype fft;
	fvalList.getType(fft);
	if (fftList == fft) 		
	{
		// End rmm8235
		EXTqlist *theList = fvalList.getList(qfalse);
		if (theList)
		{
			ECOlistFonts(theList, pIsRep);
			ECOsetParameterChanged(pEci, 1);
			delete theList;	// rmm3418
		}
	}

	// Indicate success:
	return 0;
}

// Component library entry point (name as declared in resource 31000)
extern "C" LRESULT OMNISWNDPROC FontOpsProc(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam, EXTCompInfo* eci)
{
	 // Initialize callback tables - THIS MUST BE DONE 
   ECOsetupCallbacks(hwnd, eci);		
	 switch (Msg)
	 {
	 		case ECM_CONNECT:
      {
        return ECOmakeConnectFlags(EXT_FLAG_LOADED|EXT_FLAG_ALWAYS_USABLE|EXT_FLAG_REMAINLOADED|EXT_FLAG_NVOBJECTS); // Return external flags // rmm11466
      } 
      case ECM_DISCONNECT:
      { 
        return qtrue;
      }
      // ECM_GETCOMPLIBINFO - this is sent by OMNIS to find out the name of the library, and
      // the number of components this library supports
      case ECM_GETCOMPLIBINFO:
      {
      	return ECOreturnCompInfo(gInstLib, eci, RES_LIB_NAME, 0);
      }
			case ECM_GETSTATICOBJECT:
			{
				return ECOreturnMethods( gInstLib, eci, &fontopsStaticFuncs[0], cSMethod_Count);
			}
			case ECM_METHODCALL:
			{
				return tqfFontOpsObj::staticMethod(eci);
			}
	 		case ECM_CONSTPREFIX:
			{
				EXTfldval exfldval;
				ECOaddParam(eci, &exfldval);
				str80 conPrefix; RESloadString(gInstLib, RES_CONST_PREFIX, conPrefix);
				exfldval.setChar(conPrefix);
				return qtrue;
			}
			case ECM_GETCONSTNAME:
			{
				return ECOreturnConstants(gInstLib, eci, RES_CONST_START, RES_CONST_END);
			}
			case ECM_GETVERSION:
			{
				return ECOreturnVersion(VERSION_MAJOR,VERSION_MINOR);
			}                                                                 
	 }
	 // As a final result this must ALWAYS be called. It handles all other messages that this component
	 // decides to ignore.
	 return WNDdefWindowProc(hwnd,Msg,wParam,lParam,eci);
}

// End of file
