/* $Header$ */

// 02-Mar-22	rmm11466		Implemented new build numbering and serial numbers to support Studio Now releases and periodic releases.
// 14-Jan-21	rmm_ncs			Removed unnecessary ECM_GETCOMPSTORE... messages.
// 13-Mar-20	CRMAC1014		macOS changes for 10.14 SDK and later.
// 17-Apr-08	rmm6347			ST/WT/1319	Fixed crash.
// 30-Jun-04	rmm5006			Multiple select knobs were missing from quite a few components.
// 21-Jun-04	rmm4999			Finished rmm4993: remote form fields now show $xxx correctly.
// 21 FEB 02	mpm5040			Fixes theme background for platforms other than OSX
// 20-Apr-01  MHn0144			ST/WO/1258  Fixed OSX bitmap crash.
// 07-Jun-00	rmm3775			ST/EC/488		Fixed GPF caused by empty message.
// 31-Mar-00	rmm3689			Added version resource.
// 10-Dec-99	rmm3556			Allow reverse scrolling, and use GDIdrawTextJst for text drawing.
// 04/01/1999 MHn0004			Mark external component properties for find & replace.

#include <extcomp.he>
#include <extfval.he>
#include <hwnd.he>
#include <gdi.he>
#include "marquee.he"

#include <time.h>
#include <math.h>
#include <string.h>

#define COMPONENT_COUNT 	1				/* Number of controls within library */

#ifdef isWEB
#define LIB_RES_NAME  1001		/* Resource id of library name */
#define MARQUEE_ID		2001		/* Resource id of control within library */
#else
#define LIB_RES_NAME  1000		/* Resource id of library name */
#define MARQUEE_ID		2000		/* Resource id of control within library */
#endif

#define MARQUEE_ICON 			1				/* Resource bitmap id */

const qshort
				cMarqueeMessage 		= 1,
				cMarqueeSpeed   		= 2,
				cMarqueeTextcolor   = 3,
				cMarqueeBackcolor   = 4,
				cMarqueeJumps   		= 5,
				cMarqueeFont   			= 6,
				cMarqueeFontSize   	= 7;
				// -----------------------

ECOproperty MARQUEEproperties[8] = // MHn0144
{ 
	cMarqueeMessage, 		4000, 	fftCharacter, EXTD_FLAG_FAR_SRCH, 0, 0, 0 ,		// message MHn0004
	cMarqueeSpeed,			4001,		fftInteger, 0 , 0, 0, 0,												// message speed
	cMarqueeTextcolor,	4002,		fftInteger, EXTD_FLAG_PWINDCOL , 0, 0, 0,				// text color
	cMarqueeBackcolor,	4003,		fftInteger, EXTD_FLAG_PWINDCOL , 0, 0, 0,				// back color
	cMarqueeJumps,			4004,		fftInteger, 0 , 0, 0, 0,												// message jumps
	cMarqueeFont, 			4005, 	fftInteger, EXTD_FLAG_FONTPROP, 0, 0, 0,																		// day font
	cMarqueeFontSize, 	4006, 	fftInteger, 0, 0, 0, 0,																											// day fontsize
	anumBackgroundTheme,   0,	0,			0, 0, 0, 0,	// MHn0144																										// day fontsize
};

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

tqfMarquee::tqfMarquee(HWND pFieldHWnd, qapp pApp) // rmm5347
{
	mHWnd = pFieldHWnd;
	mApp = pApp;	// rmm6347
	
	qlong style = WNDgetWindowLong( mHWnd, GWL_EXSTYLE );
	style |= WND_REDRAWONSIZE;
	WNDsetWindowLong( mHWnd, GWL_EXSTYLE, style );
	mMessage[0] = (qchar)RESloadString(gInstLib,3000,&mMessage[1],255);
	mMessageRate = 100; 
	mMessageBmp = NULL;
	mMessagePos = 0; 
	mMessageLen = 0;   
	mMessageJmps = 2;
	mToText = 0;    
	mTextColor = GDI_COLOR_QWHITE;
	mBackColor = GDI_COLOR_QBLACK;
	mFont = 1;
	mFontSize = 9;
	WNDsetTimer( mHWnd, 101, (qushort)mMessageRate );
	mNumberHwnd = 0; // rmm4999
	rebuildMessage();
	// Start rmm4999
	if (ECOisDesign(mHWnd))
	{
		qrect clientRect;
		WNDgetClientRect(mHWnd, &clientRect);
		qrect numberRect(clientRect);
		clientRectToNumberRect(numberRect);

		qpen borderPen(1, GDI_COLOR_WINDOWTEXT);
		WNDborderStruct border(WND_BORD_PLAIN, borderPen);

		mNumberHwnd = WNDcreateWindow(mHWnd, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, WNDgetProcInst(mHWnd), &numberRect, &border);

		WNDshowWindow(mNumberHwnd, ECOisShowNumber(mHWnd) ? SW_SHOW : SW_HIDE);
	}
	// End rmm4999
}

tqfMarquee::~tqfMarquee()
{    
	if ( mMessageBmp )
		GDIdeleteBitmap(mMessageBmp);
	mMessageBmp = NULL;
	if (mNumberHwnd) WNDdestroyWindow(mNumberHwnd); // rmm4999
}

// rmm4999: added this method
void tqfMarquee::clientRectToNumberRect(qrect &pRect)
{
	qdim width = pRect.width();
	pRect.left = 2;
	pRect.right = pRect.left + width/2;
}

qlong tqfMarquee::attributeSupport( LPARAM pMessage, WPARAM wParam, LPARAM lParam, EXTCompInfo* eci )
{
	switch( pMessage )
	{ 
		case ECM_PROPERTYCANASSIGN: 
		{
			return 1L;
		}
		case ECM_SETPROPERTY: 
		{       
			EXTParamInfo* param = ECOfindParamNum( eci, 1 );
			if ( param )
			{
				EXTfldval fval( (qfldval)param->mData );
				switch( ECOgetId(eci) )
				{
					case cMarqueeMessage: 				
					{
						qlong len = 0;
						fval.getChar(255, &mMessage[1], len );
						mMessage[0] = (qchar)len;
						rebuildMessage();
						break; 			
					}
					case cMarqueeSpeed:		
					{
						WNDkillTimer( mHWnd, 101 );
						mMessageRate = fval.getLong(); 
						if ( mMessageRate )
							WNDsetTimer( mHWnd, 101, (qushort)mMessageRate );
						break;
					}
					case cMarqueeTextcolor:
					{
						mTextColor = (qcol)fval.getLong();
						rebuildMessage();
						break; 			
					} 
					case cMarqueeBackcolor:
					{
						mBackColor = (qcol)fval.getLong();
						rebuildMessage();
						break;
					} 
					case cMarqueeJumps:
					{
						mMessageJmps = fval.getLong(); 
						break;
					}
					case cMarqueeFont:
					{
						mFont = ECOgetFontIndex(mHWnd,fval);
						rebuildMessage();
						break;
					}
					case cMarqueeFontSize:
					{
						mFontSize = (qshort) fval.getLong(); 
						rebuildMessage();
						break;
					}
					default: // MHn0144
						return 0L; // MHn0144
				}       
				WNDinvalidateRect( mHWnd, NULL );
				WNDupdateWindow( mHWnd );
				return 1L;
			}
			break;
		}
		case ECM_GETPROPERTY: 
		{
			EXTfldval fval;
			switch( ECOgetId(eci) )
			{
				case cMarqueeMessage: 		fval.setChar( mMessage ); break; 			
				case cMarqueeSpeed: 			fval.setLong( mMessageRate ); break; 			
				case cMarqueeTextcolor:		fval.setLong( mTextColor ); break; 			
				case cMarqueeBackcolor:		fval.setLong( mBackColor ); break; 			
				case cMarqueeJumps:				fval.setLong( mMessageJmps ); break; 			
				case cMarqueeFont:				fval.setLong( mFont ); break; 			
				case cMarqueeFontSize:		fval.setLong( mFontSize ); break; 			
				default: return 0L; // MHn0144		
			}         
			ECOaddParam(eci,&fval);
			return 1L;
		}
	}
	return 0;
}

// rmm3556: several changes in this method - now called in 2 passes, the first to draw and determine the
// width of the text, the second to actually create the bitmap.
void tqfMarquee::rebuildMessage(qdim pTextWidth)
{
	// Start rmm4999: moved some of this so that it occurs on OSX, and resized number HWND
	qrect client;
	WNDgetClientRect( mHWnd, &client );

	qfnt fnt;
	ECOgetFont( mHWnd, &fnt, (qshort)mFont, (qshort)mFontSize );

	if (mNumberHwnd)
	{
		qrect numberRect(client);
		clientRectToNumberRect(numberRect);
		qdim fontHeight = GDIfontHeight(&fnt);
		qdim maxNumberHeight = fontHeight + 4;
		if (numberRect.height() > maxNumberHeight)
		{
			numberRect.bottom = numberRect.top + maxNumberHeight - 1;
		}
		WNDmoveWindow(mNumberHwnd, numberRect.left, numberRect.top, numberRect.width(), numberRect.height(), qtrue);
	}
	// End rmm4999
#ifndef ismacosx // MHn0144
	if (!mMessage[0]) mMessage.concat(' ');	// rmm3775
	
	if ( mMessageBmp )
	{
		GDIdeleteBitmap(mMessageBmp);
		mMessageBmp = NULL;
	}
	
	HDC hdc = GDIgetTempDC();

	HFONT font = GDIcreateFont( &fnt, styPlain );
	HFONT oldfont = GDIselectObject( hdc, font );
	
	qdim ht = GDIfontHeight( hdc );
	
	mBitmapRect.left = mBitmapRect.top = 0; 
	mBitmapRect.right = pTextWidth + ( client.width() * 2 ) - 1;
	mBitmapRect.bottom = ht;
	
	mMessageBmp = GDIcreateBitmap( mBitmapRect.width(), mBitmapRect.height(), 0 );
	
	HBITMAP oldbmp = GDIselectBitmap( hdc, mMessageBmp );
	
 	mMessageLen = pTextWidth + ( client.width() );
 	mToText = client.width();
 	
	if ( !WNDdrawThemeBackground( mHWnd, hdc, &mBitmapRect, WND_BK_DEFAULT )  ) // mpm5040
	{
 		GDIsetTextColor( hdc, mBackColor );
		GDIfillRect( hdc, &mBitmapRect, GDIgetStockBrush( BLACK_BRUSH ) );
	}
  
	GDItextSpecStruct textSpec(fnt, styPlain, mTextColor);
	GDIdrawTextStruct drawText(hdc, pTextWidth ? client.width() : 0, 0, &mMessage[1], mMessage.length(), &textSpec, 0, 0, qtrue, mApp, 0);
  GDIdrawTextJst(&drawText);

	GDIselectBitmap( hdc, oldbmp );

	GDIselectObject( hdc, oldfont );  
	GDIdeleteObject( font );

	if (!pTextWidth) rebuildMessage(drawText.mX);
#endif // MHn0144
}

#ifdef ismacosx // MHn0144 begins
void tqfMarquee::drawMessage(WNDpaintStruct *pPaintStruct)
{
	void *offscreenPaintInfo = 0; 
	HDC tmpDC = pPaintStruct->hdc;
	qrect rcPaint = pPaintStruct->rcPaint;
	if (!mMessage[0]) mMessage.concat(' ');	// rmm3775

	qrect client, offsetRect;
	WNDgetClientRect( mHWnd, &client );
 	mToText = client.width();
	if ( mMessageRate==0 )
		mMessagePos = mToText;	
	offsetRect = client;

	qfnt fnt;
	ECOgetFont( mHWnd, &fnt, (qshort)mFont, (qshort)mFontSize );
	HFONT font = GDIcreateFont( &fnt, styPlain );
	HFONT oldfont = GDIselectObject( tmpDC, font );	 	
	qdim ht = GDIfontHeight( pPaintStruct->hdc );
	qshort offset = ( client.height() / 2 ) - ( ht / 2 );
	GDIoffsetRect( &offsetRect, (client.right-mMessagePos), offset );
	
	offscreenPaintInfo = GDIoffscreenPaintBegin( NULL, tmpDC, client, rcPaint );
	if (offscreenPaintInfo)
	{
		if ( !WNDdrawThemeBackground( mHWnd, tmpDC, &client, WND_BK_DEFAULT )  ) // MHn0143
		{
	 		GDIsetTextColor( tmpDC, mBackColor );
			GDIfillRect( tmpDC, &offsetRect, GDIgetStockBrush( BLACK_BRUSH ) );
		}
	  
		GDItextSpecStruct textSpec(fnt, styPlain, mTextColor);
		GDIdrawTextStruct drawText(tmpDC, offsetRect.left, offsetRect.top, &mMessage[1], mMessage[0], &textSpec, 0, 0, qtrue, mApp, 0);
		GDIdrawTextJst(&drawText);
	 	mMessageLen = GDItextWidth(&mMessage[1], mMessage[0], &textSpec) + ( client.width());
		GDIoffscreenPaintEnd( offscreenPaintInfo );
	}	
	GDIselectObject( tmpDC, oldfont );  
	GDIdeleteObject( font );
}
#endif // MHn0144 ends

void tqfMarquee::update()
{                            
	BLOCKVAR qrect client;	// CRMAC1014
	WNDgetClientRect( mHWnd, &client ); 
	
	if ( !mMessageBmp )
	{
		HDC fieldhdc = WNDstartDraw( mHWnd );
		if ( !WNDdrawThemeBackground( mHWnd, fieldhdc, &client, WND_BK_DEFAULT )  ) // mpm5040
		{
 			GDIsetTextColor( fieldhdc, mBackColor );
			GDIfillRect( fieldhdc, &client, GDIgetStockBrush( BLACK_BRUSH ) );
		}
		ECOdrawMultiKnobs(mHWnd, fieldhdc);	// rmm5006
		WNDendDraw( mHWnd, fieldhdc );
		return;
	}
	
	if ( mMessageRate==0 )
		mMessagePos = mToText;	
	
	HDC hdc = GDIgetTempDC();
	HBITMAP oldBmp = GDIselectBitmap( hdc, mMessageBmp );
	
	HDC fieldhdc = WNDstartDraw( mHWnd );
	qrect bitmapRect1 = mBitmapRect;
	qshort offset = ( client.height() / 2 ) - ( mBitmapRect.height() / 2 );
	GDIoffsetRect( &bitmapRect1, -mMessagePos, offset );
	ECOexcludeToolTipRect( mHWnd, fieldhdc );	// PK4712
	GDIcopyBits( hdc, fieldhdc, &mBitmapRect, &bitmapRect1, qfalse );
	ECOdrawMultiKnobs(mHWnd, fieldhdc);	// rmm5006
	WNDendDraw( mHWnd, fieldhdc );
	
	GDIselectBitmap( hdc, oldBmp );
}       

void tqfMarquee::incPos()
{
	mMessagePos+=mMessageJmps;
	if ( mMessagePos>=mMessageLen )
		mMessagePos = 0;
	// Start rmm3556
	else if (mMessageJmps < 0 && mMessagePos < 0)
		mMessagePos = mMessageLen;
	// End rmm3556
	// MHn0144 begins
	#ifdef ismacosx
		WNDinvalidateRect( mHWnd, NULL ); // MHTEST
	#endif
	// MHn0144 ends
}

qbool tqfMarquee::paint(HWND pHwnd) // rmm4999
{
	WNDpaintStruct paintStruct;
	WNDbeginPaint( pHwnd, &paintStruct ); // rmm4999
	// Start rmm4999
	if (mNumberHwnd == pHwnd)
	{
		ECOdrawNumber(pHwnd, paintStruct.hdc);
	}
	else
	{
		// End rmm4999
		// MHn0144 begins
		#ifdef ismacosx	
			drawMessage(&paintStruct); 
			ECOdrawMultiKnobs(pHwnd, paintStruct.hdc);	// rmm5006
		#endif
		// MHn0144 ends
	}
	WNDendPaint( pHwnd, &paintStruct );	 // rmm4999
	#ifndef ismacosx // MHn0144
		if (mHWnd == pHwnd) update(); // rmm4999
	#endif // MHn0144
	return qtrue;
}

// MHn0144 begins
void tqfMarquee::getBackgroundTheme()
{
	qlong lTheme;
	EXTfldval fval;
	lTheme = WNDgetWindowLong(mHWnd,GWL_BKTHEME);
	ECOgetProperty( mHWnd, anumBackgroundTheme, fval );	
	if (lTheme != fval.getLong()) WNDsetWindowLong( mHWnd, GWL_BKTHEME, fval.getLong() );	
}
// MHn0144 ends

// rmm4999:
tqfMarquee *tqfMarquee::objectFromHwnd(HWND pHwnd, EXTCompInfo *eci)
{
	tqfMarquee *object = (tqfMarquee *) ECOfindObject(eci, pHwnd);
	// Look for number hwnd, if hwnd does not locate the object
	if (!object)
	{
		HWND parentHwnd = WNDgetParent(pHwnd);
		if (parentHwnd) object = (tqfMarquee *) ECOfindObject(eci, parentHwnd);
	}
	return object;
}

extern "C" LRESULT OMNISWNDPROC GenericWndProc( HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam, EXTCompInfo* eci )
{
   ECOsetupCallbacks(hwnd, eci);
	 switch (Msg)
	 {
	 		case ECM_CONNECT: /* Omnis connection to library - allocate any global memory/classes etc... */
    	{
				#ifdef isRCCDESIGN
	  	    return EXT_FLAG_LOADED|EXT_FLAG_ALWAYS_USABLE|EXT_FLAG_REMAINLOADED; // Return external flags	// rmm_thindl
				#else
			    return ECOmakeConnectFlags(EXT_FLAG_LOADED); // rmm11466
				#endif
    	}
			case ECM_ISUNICODE:	// rmmuni
			{
				return qtrue;
			}
			case WM_WINDOWPOSCHANGED:
			{
				tqfMarquee* object = tqfMarquee::objectFromHwnd(hwnd, eci); // rmm4999
				if (object && object->hwnd() == hwnd)  // rmm4999
					object->rebuildMessage();
				break;
			}
			case WM_TIMER:							
			{	           
				tqfMarquee* object = tqfMarquee::objectFromHwnd(hwnd, eci); // rmm4999
				if (object && object->hwnd() == hwnd)  // rmm4999
				{
					object->incPos();
					#ifndef ismacosx // MHn0144
						object->update(); 
					#endif // MHn0144
				}
				return qfalse;
      }
			case WM_ERASEBKGND:
			{
				HDC hdc = (HDC)wParam; qrect client;
				WNDgetClientRect( hwnd, &client );
				tqfMarquee* object = tqfMarquee::objectFromHwnd(hwnd, eci); // rmm4999
				// Start rmm4999
				if (object && object->numberHwnd() == hwnd)
				{
					GDIsetTextColor(hdc, GDI_COLOR_WINDOW);
					GDIfillRect(hdc, &client, GDIgetStockBrush(BLACK_BRUSH));
				}
				else
				{
					// End rmm4999
					if ( !WNDdrawThemeBackground( hwnd, hdc, &client, WND_BK_DEFAULT )  ) // mpm5040
					{
						if ( object )
							GDIsetTextColor( hdc, object->backColor() );
						GDIfillRect( hdc,  &client, GDIgetStockBrush( BLACK_BRUSH) );
					}
				}
				return 1L;
			}
			case WM_PAINT:							
			{
				tqfMarquee* object = tqfMarquee::objectFromHwnd(hwnd, eci); // rmm4999
				if ( object && object->paint(hwnd) ) // rmm4999
					return qtrue;
				break;
			}
			case ECM_OBJCONSTRUCT:				/* Construct an object */
			{
				tqfMarquee* object = new tqfMarquee(hwnd, ECOgetApp(eci->mInstLocp)); // rmm6347
				ECOinsertObject( eci, hwnd, (void*)object );
				return qtrue;
			}
			case ECM_OBJDESTRUCT:					/* Destruct the object */
			{
				WNDkillTimer( hwnd, 101 );
				tqfMarquee* object = (tqfMarquee*)ECOremoveObject( eci, hwnd );
				if ( object ) delete object;              
				return qtrue;
			}
			case ECM_PROPERTYCANASSIGN:  	/* Object: Is the property assignable (ie readonly?) */
			case ECM_SETPROPERTY: 				/* Object: Assignment to a property */
			case ECM_GETPROPERTY:					/* Object: Retrieve value from property */
			{
				tqfMarquee* object = (tqfMarquee*)ECOfindObject( eci, hwnd );
				if ( object )
					return object->attributeSupport( Msg, wParam, lParam, eci );
				return 0L;
			}
			// MHn0144 begins
	    case WM_FLD_FILLCHANGED:	// anumForecolor,anumBackcolor,anumBackpattern
	    case WM_FLD_FONTCHANGED:	// anumFont,anumFontsize,anumFontstyle,anumAlign,anumTextColor
	    {
				tqfMarquee* object = (tqfMarquee*)ECOfindObject( eci, hwnd );
				if ( object )
				{
 					object->getBackgroundTheme();
					object->rebuildMessage(); // mpm5040
				}
 				break;
		  }
	    case ECM_OBJINITIALIZE:
	    {
 				if ( wParam )
 				{
 					tqfMarquee* object = (tqfMarquee*)ECOfindObject( eci, hwnd );
 					if ( object )
 					{
 						object->getBackgroundTheme();	
 					}
 				}
 				return qtrue;
		  }
			// MHn0144 ends
      case ECM_GETCOMPLIBINFO:
      {
      	return ECOreturnCompInfo( gInstLib, eci, LIB_RES_NAME, COMPONENT_COUNT );
      }
			case ECM_GETCOMPICON:
			{ 	
				if ( eci->mCompId==MARQUEE_ID ) return ECOreturnIcon( gInstLib, eci, MARQUEE_ICON );
				return qfalse;
			}
			case ECM_GETCOMPID:
			{
				if ( wParam==1 )
					return ECOreturnCompID( gInstLib, eci, MARQUEE_ID, cObjType_Basic );
				return 0L;
			}
			case ECM_GETPROPNAME:
			{
				return ECOreturnProperties( gInstLib, eci, &MARQUEEproperties[0], 8 ); // MHn0144
			}
			case ECM_GETVERSION:
			{
				return ECOreturnVersion(gInstLib); // rmm3689
			}                                                                 
			case WM_FLD_DESIGN: // rmm4999
			{
				tqfMarquee *object = (tqfMarquee *) ECOfindObject(eci, hwnd);
				if (object && object->numberHwnd())
				{
					switch (wParam)
					{
						case DSGN_ORDERCHANGED:
						{
							WNDinvalidateRect(object->numberHwnd(), NULL);
							return 0;
						}
						case DSGN_DRAWNUMBER:
						{
							WNDshowWindow(object->numberHwnd(), lParam ? SW_SHOW : SW_HIDE);
							break;
						}
					}
				}
				break;
			}
	 }
	 return WNDdefWindowProc(hwnd,Msg,wParam,lParam,eci);
}
// End of file
