// $Header$

/*************** changes *******************
Date			Edit				Bug					Description
08-Jan-25	bjw0780									Allow $moveitem (and similar props) to be set when the design window is closed.
13-Apr-22	rmm11531								Undo for $move... properties that move an entry in a control to a new position.
26-Oct-20	rmm10726		ST/CO/306		Conversion to 10.2 added an item to empty component item lists.
23-Oct-20	rmm10721								Crash at startup running Windows 32 bit.
10-Oct-19	jmg0935									Added mouse-related virtual methods.
10-Oct-19	jmg0934									Added component initialised handling.
10-Oct-19 jmgxcompw								Fixed some warnings associated with jmgxcomp.
09-Oct-19	jmgxcomp								Created this class.
-----------------------------------------------------
03-Oct-14	rmm8441									Navigation menu control.
14-Feb-13	rmm7847									Additional calls to jniObjectSelected for Omnis X to cater for tab changing etc on design window.
03-Oct-11	rmm7262			ST/BE/644		Design mode redraw issue.
01-Mar-11	rmm7095									JavaScript client data grid component.
18-Jan-11	rmm7072									JavaScript label server component.

*******************************************/

#pragma once

#include "extcomp.he"
#include "gdi.he"
#include "hwnd.he"
#include <unordered_map>
#include "AutoPropertyValues.h"
#include "omnisCompFmtNotation.h"

class ComponentDelegate;

typedef LRESULT(OMNISWNDPROC *wndProcFunction)(HWND, UINT, WPARAM, LPARAM, EXTCompInfo*);	// rmm10721: OMNISWNDPROC (__stdcall changes the parameter passing convention used by 32 bit Windows)

/** The (base) static definition of a particular Omnis component type */
struct OMNISControlDefinition {
	qlong								mLibResName;					///< Resource number of library
	qlong								mObjectID;						///< External component object id
	qlong								mIconID;							///< ICON id for control
	qlong								mEventCount;					///< Count of events
	ECOmethodEvent*			mEvents;							///< Control events
	qlong								mPropertyCount;				///< Count of properties
	ECOproperty*				mProperties;					///< Control properties
	qlong								mFirstConstant;				///< First constant resource; zero if no constants
	qlong								mLastConstant;				///< Last constant resource; zero if no constants
	qlong								mCompStoreGroupRes;		///< Resource number of component store group
	qlong								mCustomTabName;				///< Resource number of custom tab
	qlong								mMethodCount;					///< Count of methods
	ECOmethodEvent*			mMethods;							///< Control methods
	wndProcFunction			mWndProc;							///< Function pointer to the component's WndProc
	FMTclassMakeFunc		mMakeFmtClass;				// Function to make class notation object
	qlong								mExtraPropertyCount;	///< Count of extra properties. Can be automatically populated by responding to ECM_GET_EXTRA_PROPS
	ECOproperty* mExtraProperties;						///< Extra properties for this control. Can be automatically populated by responding to ECM_GET_EXTRA_PROPS
	std::unordered_map<attnumber, ECOproperty*> mAutoProps; ///< An (auto-generated) map of property numbers to property definitions which should be handled automatically (those with EXTD_EFLAG_AUTOPROP).
};

class OmnisComponent
{
#pragma region variables

public:
	ComponentDelegate* mDelegate = 0;

protected:
	HWND mHWnd; ///< The component's HWND window.
	tqappfile* mApp;
	OMNISControlDefinition* mControlDef;
	GDItextSpecStruct mTextSpec; 	///< The field's font, textcolor etc.
	qbool mNoDesignName;	// If true, do not draw object name in design mode
	AutoPropertyValues mAutoPropValues;
	qbool	mReadOnly;			// rmm8441: Read-only state of the field
	qbool	mIsActive;			// rmm8441: Active state of the field
	qbool mObjectInitComplete;	// jmg0934: True once the object has been constructed and properties set.
	qbool	mMustHaveItem;				// rmm10726: If true,the item list must have at least one item

	EXTqlist*		mItemList; ///< Used by components which store a list of items (E.g segmented control), so properties can be set on each item in the list.
	int					mMaxItems;


private:
	// Start rmm7095
	HWND mPaintHwnd;
	qrect mRcPaint;
	EXTCompInfo* mPaintEci;
	// End rmm7095
#pragma endregion variables


#pragma region methods

public:
	OmnisComponent(HWND pHWnd, OMNISControlDefinition* pControl, ComponentDelegate* pCompDelegate = 0);
	HWND hwnd() { return mHWnd; }

	GDItextSpecStruct& textSpec() { return mTextSpec; }
	void setTextSpec(GDItextSpecStruct* pTextSpec);
	HWND getPaintHwnd() { return mPaintHwnd; }	// rmm7095
	qrect& getRcPaint() { return mRcPaint; }		// rmm7095
	EXTCompInfo* getPaintEci() { return mPaintEci; }	// rmm7095

	virtual void inval();

	virtual qlong attributeSupport(LPARAM pMessage, WPARAM wParam, LPARAM lParam, EXTCompInfo* eci) { // jmgxcompw: Made public
		GDIignore(&pMessage); GDIignore(&wParam); GDIignore(&lParam); GDIignore(&eci);
		return qfalse; // rmm7072: qfalse means nothing was processed (was qtrue)
	}

	static void getListProperty(EXTqlist& pList, qlong pLineNumber, qshort pColumn, ffttype pFft, EXTfldval& pPropertyValue);
	static void setListProperty(EXTqlist& pList, qlong pLineNumber, qshort pColumn, ffttype pFft, EXTfldval& pPropertyValue, qlong pMinInteger = EXT_NOT_SPECIFIED, qlong pMaxInteger = EXT_NOT_SPECIFIED);
	static void setListProperty(EXTqlist& pList, qlong pLineNumber, qshort pColumn, ffttype pFft, EXTCompInfo* eci, qlong pMinInteger = EXT_NOT_SPECIFIED, qlong pMaxInteger = EXT_NOT_SPECIFIED);

	// Start item list
	// These methods are used by controls which have a list of items e.g. the segmented control
	void deleteList();
	void newItemList(fldval* pFval);

	qbool setItemList(EXTfldval& fval);
	qbool getItemList(EXTfldval& fval);

	qbool setCurrentItem(EXTfldval& fval, qbool pUsingMouse = qfalse) { return setCurrentItem(fval.getLong(), pUsingMouse); }	// rmm7847
	qbool setCurrentItem(qlong pCurrentItem, qbool pUsingMouse = qfalse); // rmm7847
	qbool getCurrentItem(EXTfldval& fval);

	qbool setItemCount(EXTfldval& fval) { return setItemCount(fval.getLong()); }
	qbool setItemCount(qlong pItemCount);
	qbool getItemCount(EXTfldval& fval);

	qbool moveItem(EXTfldval& fval, rstrno pMovePropertyResource, attnumber pMovePropertyAnum = 0, str255 *pMovePropertyName = 0); // rmm11531
	
	static qbool moveItemInList(EXTqlist* pList, qlong pOldNumber, qlong pNewNumber); // bjw0780

protected:
	virtual void initDefaults();
	/** Called once the object has constructed and properties been set. */
	virtual void initComplete() {} // jmg0934

	/** Implement in child class to handle inserting of child controls, if it is a container component. */
	virtual void insertOtherObjects(EXTCompInfo* pEci) { GDIignore(&pEci); }	// mpm_cw // rmm7095
	/** Implement in child class to handle removal of child controls, if it is a container component. */
	virtual void removeOtherObjects(EXTCompInfo* pEci) { GDIignore(&pEci); }	// mpm_cw // rmm7095
	/** Implement in child class to be notified when the textSpec changes */
	virtual void textSpecChanged() {};
	virtual void setDefaults(qbool pEnabled) { GDIignore(&pEnabled); }
	virtual void paintDesign(HDC pHdc); // mpm_cw
	virtual void paintRuntime(HDC pHdc); // rmm8441
	virtual HWND getDesignNameHwnd() { return mHWnd; }	// rmm7095
	
	virtual omnisComponent_formatNotation* createFormatNotationClass();
	virtual qbool hasFormatNotationClass() { return mControlDef->mMakeFmtClass != NULL; }

	// Start jmg0935
	/** Called with mouse event messages. Return qtrue if you have handled the message and to prevent the message going any further. */
	virtual qbool mouse(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam, EXTCompInfo* eci)
	{
		GDIignore(&hwnd); GDIignore(&Msg); GDIignore(&wParam); GDIignore(&lParam); GDIignore(eci);
		return qfalse;
	}

	virtual void captureChanged() {}
	virtual void captureAbort() {}
	// End jmg0935

	static void AddAutoPropsToDefinition(OMNISControlDefinition* pDefinition, ECOproperty* pPropArray, qlong pPropCount);

	/**
	 Called to check whether an automatically handled property (EXTD_EFLAG_AUTOPROP) can be assigned.
	 
	 If not implemented, auto properties will default to assignable.
	
	 @param [in]	propNumber 		The property number.
	 @param [out]	didHandle 		Set to true if you have handled the	case for this property, false if not.
	
	 @returns	{qbool} Whether the property can be assigned.
	*/
	virtual qbool canAssignAutoProperty(attnumber propNumber, qbool& didHandle) {
		GDIignore(&propNumber); // jmgxcompw
		didHandle = qtrue; return qtrue;
	};
	// qbool inbuiltOverrideAutoProperty(attnumber propNumber); // Based on a flag in ECOPropertyEx Just handle in attribsupport()?

	virtual qbool getAutoProperty(ECOproperty* propertyDef, EXTfldval *returnVal) {
		return mAutoPropValues.getProperty(propertyDef, returnVal);
	}
	
	virtual qbool setAutoProperty(ECOproperty* propertyDef, EXTfldval* newValue) {
		return mAutoPropValues.setProperty(propertyDef, newValue);
	}

	/**
	 Notifies a component that an automatically handled property's value has changed.

	 To run default behaviour, call OmnisComponent::autoPropertyChanged()
	
	 @param [in]		propertyDef 		The property's definition.
	 */
	virtual void autoPropertyChanged(ECOproperty* propertyDef);

	void setRedrawOnSize();	// rmm7262

	virtual void enabledChanged(qbool pEnabled) { GDIignore(&pEnabled); } // mpm_cw
	virtual void fillChanged() {}	// rmm8441
	virtual qbool sizeChanged() { return qfalse; }	// rmm8441


private:
	qbool paint(EXTCompInfo* eci, HWND pHwnd); // rmm7095
	qbool getAutoProperty(ECOproperty* propertyDef, EXTCompInfo* eci);
	qbool setAutoProperty(ECOproperty* propertyDef, EXTCompInfo* eci);

#pragma endregion methods

	friend LRESULT OMNISComponentDefWindowProc(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam, EXTCompInfo* eci, OMNISControlDefinition* pControl);
};


/** The default window message handler for OmnisComponents. */
LRESULT OMNISComponentDefWindowProc(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam, EXTCompInfo* eci, OMNISControlDefinition* pControl);
