//========================================================================
// Reusable plugin manager
//
// AUTHOR:  Gabor Nagy
// DATE:    2026-Jun-10 21:57:01
//
// Copyright (C) 1996-2026 by Gabor Nagy. All rights reserved.
//========================================================================
#ifndef EMalloc_h
#include <EMalloc.h>
#endif	// EMalloc_h

#include <Xe/XeP.h>
#include <Xe/DropDownPanel.h>
#include <Xe/Shell.h>
#include <Xe/Dialog.h>

#define XeDebugTOGGLEBUTTON  0

static XeWidget  _PluginManagerDialogW = NULL;


static XeDrawer  _Folders[64];static int  _NumOfFolders = 0;


static XeWidget  _PluginsClipWindowW = NULL,       // ScrolledWindow's ClipWindow widget
                 _PluginsScrolledWindowW = NULL,   // ScrolledWindow Widget
                 _PluginsVScrollbarW = NULL,
                 _PluginsTopMatrixW = NULL,
                 _PluginInfoLabelW = NULL;

static XeWidget  _PluginInfoDialogW = NULL;

typedef struct
{
	EPlugin*  Plugin;
	XeWidget  LabelW, LoadedBW, AutoLoadBW, InfoBW;
	EBool     Loaded;
} EPluginM;


static EPluginM*   _InfoPlugin = NULL;  // The plugin with its info shown
static EPluginM**  _AccessiblePluginsM = NULL;static int  _MaxNumOfAccessiblePluginsM = 0;


static void  _CB_PluginManagerInfo(XeWidget PW, EPointer PClientData, EPointer PCallData);

static const int  _NColumns = 4;

//========================================
// Plugin manager dialog callbacks
//========================================
static void EguiCB_PluginManager(XeWidget PW,  EPointer PClientData,  EPointer PCallData)
{
	XeCallbackStruct*  LCBS = (XeCallbackStruct*)PCallData;
	if(LCBS->Reason == XeCR_PROTOCOLS)
	{
		switch((EPointerInt)PClientData)
		{
			case XeCR_OK:
			break;

			case XeCR_CANCEL:
				XeWidget_Unmap(_PluginManagerDialogW);
			break;
		}
	}
}


//========================================
// Init PluginMRec
//========================================
static void E3dp_InitPluginMRec(EPluginM* PPluginM)
{
	PPluginM->Plugin = NULL;
	PPluginM->Loaded = FALSE;
	PPluginM->LabelW = NULL;
	PPluginM->LoadedBW = NULL;
	PPluginM->AutoLoadBW = NULL;
}


//========================================
// Load/Unload plugin
//========================================
static void _CBPluginManager_LoadUnload(XeWidget PW, EPointer PClientData, EPointer PCallData)
{
	EPluginM*  LPluginM = (EPluginM*)PClientData;
	EPlugin*   LPlugin = LPluginM->Plugin;

	if(((XeToggleButtonCallbackStruct*)PCallData)->Set)
	{
//  E3dp_PrintMessage(ELogMESSAGE, 2500, "Loading plugin: %s", LPluginM->Plugin->DSOName);
// Load plugin
//
		if(!LPluginM->Loaded)
		{
			LPlugin->Load = TRUE;
			E_PluginLoad(LPlugin, NULL, EPluginFromUI);

			if(LPlugin->DLHandle == NULL) XeToggleButton_SetState(PW, FALSE, FALSE);
			else
			{
/*
				LPlugin->InitFunction(LPluginM->Plugin);
*/
				LPluginM->Loaded = TRUE;
//				E3dp_PrintMessage(ELogMESSAGE, 2500, "Loaded plugin: %s", LPluginM->Plugin->DSOName);
			}

// If the info for this plugin is being shown, update it
//
			if(_InfoPlugin == LPluginM) _CB_PluginManagerInfo(NULL, (EPointer)LPluginM, NULL);
		}
	}
	else
	{
// Unload plugin
//
		if(LPluginM->Loaded)
		{
			LPlugin->Load = FALSE;

			if(LPlugin->Locks_Count > 0)
			{
				E_PrintMessage(0, 10000, "Plugin \"%s\" is in use, it would be unsafe to unload it. Check if the plugin has any dialog-boxes open!", LPluginM->Plugin->Name);
				XeToggleButton_SetState(PW, TRUE, FALSE);
				return;
			}

			E_PluginUnload(LPlugin, EPluginFromUI);

			LPluginM->Loaded = FALSE;
//printf("[%s] Unloaded\n", LPluginM->Plugin->DSOName);fflush(stdout);

// If the info for this plugin is being shown, update it
//
			if(_InfoPlugin == LPluginM) _CB_PluginManagerInfo(NULL, (EPointer)LPluginM, NULL);
		}
	}
}


//========================================
// Auto-load plugin
//========================================
static void _CBPluginManager_AutoLoad(XeWidget PW, EPointer PClientData, EPointer PCallData)
{
	EPluginM*  LPluginM = (EPluginM*)PClientData;
	EPlugin*   LPlugin = LPluginM->Plugin;

	if(((XeToggleButtonCallbackStruct*)PCallData)->Set)
	{
		if(!LPluginM->Loaded)
		{
			LPlugin->AutoReload = TRUE;
		}
	}
	else LPlugin->AutoReload = FALSE;
}


//========================================
// Plugin info dialog callback
//========================================
static void _CB_PluginInfo(XeWidget PW, EPointer PClientData, EPointer PCallData)
{
	XeCallbackStruct*  LCBS = (XeCallbackStruct*)PCallData;
	if(LCBS->Reason == XeCR_PROTOCOLS)
	{
		switch((EPointerInt)PClientData)
		{
			case XeCR_CANCEL:
				XeWidget_Unmap(_PluginInfoDialogW);
				_InfoPlugin = NULL;
			break;
		}
	}
}


//========================================
// Plugin info button callback
//========================================
static void _CB_PluginManagerInfo(XeWidget PW, EPointer PClientData, EPointer PCallData)
{
	EPluginM*  LPluginM = (EPluginM*)PClientData;
	EPlugin*   LPlugin = LPluginM->Plugin;
	char*      LInfo = LPlugin->Info;if(LInfo == NULL) LInfo = "-";
	char       LStatusString[2048];LStatusString[0] = 0;
	uint32_t   LStatusColor;

	const EBool  LDarkMode = XeColorTheme_IsDark();

	if(LPluginM->Loaded)
	{
		strcpy(LStatusString, " Successfully loaded");LStatusColor = LDarkMode ? EcRGBAp8Color_i(0x00C000FF) : EcRGBAp8Color_i(0x006000FF);
	}
	else
	{
		if(LPlugin->ErrorMessage == NULL)
		{
			strcpy(LStatusString, " Not loaded / unloaded by user");LStatusColor = LDarkMode ? EcRGBAp8Color_i(0xB0B0B0FF) : EcRGBAp8Color_i(0x404040FF);
		}
		else
		{
			sprintf(LStatusString, " Falied to load. Reason:\n %s", LPlugin->ErrorMessage);LStatusColor = LDarkMode ? EcRGBAp8Color_i(0xF0B070FF) : EcRGBAp8Color_i(0x600000FF);
		}
	}

	char  LTmpStr[4096];sprintf(LTmpStr, "/%s.so\n\nStatus:\n%s\n\nUser interface:\n", LPlugin->DSOName, LStatusString);

	const uint32_t  LBlue  = LDarkMode ? EcRGBAp8Color_i(0x40A0FF0F) : EcRGBAp8Color_i(0x000080FF);
	const uint32_t  LLabelColor  = Ec_RGBAiToRGBAp8(&Xe_ForegroundRGBAiColor);

	XeString  LXeStr = XeString_NewVa(TRUE,  XeFONT, XeFontDEFAULT, XeALIGNMENT, XeStringAlignLEFT,
	 XeCOLOR_RGBA, LLabelColor,  XeTEXT, "Name\n",
	 XeCOLOR_RGBA, LBlue,   XeTEXT, LPlugin->Name,
	 XeCOLOR_RGBA, LLabelColor,  XeTEXT, "\n\nInfo\n",
	 XeCOLOR_RGBA, LBlue,   XeTEXT, LInfo,
	 XeCOLOR_RGBA, LLabelColor,  XeTEXT, "\n\nExecutable\n ",
	 XeCOLOR_RGBA, LBlue,   XeTEXT, LPlugin->PathName, XeTEXT, EStrSLASH_STRING, XeTEXT, LPlugin->DSOName, XeTEXT, ".so",
	 XeCOLOR_RGBA, LLabelColor,  XeTEXT, "\n\nStatus\n",
	 XeCOLOR_RGBA, LStatusColor, XeTEXT, LStatusString,
	 0);

	EArg  Args[64];int  ArgCnt;

	if(_PluginInfoDialogW == NULL)
	{
		EXeStart;
		EXeSetArg(XeNAllowShellResize, TRUE);
		EXeSetArg(XeNMinSizeX, 240);EXeSetArg(XeNMinSizeY, 160);
		EXeSetArg(XeNWMDecorations, XeWMDecorCLOSE|XeWMDecorBORDER|XeWMDecorRESIZEH|XeWMDecorTITLE|XeWMDecorMINIMIZE);
		EXeSetArg(XeNCreateButtons, FALSE);
		EXeSetArg(XeNTitle, "Plugin info");EXeSetArg(XeNIconName, "Plugin info");
		EXeSetArg(XeNCustomItemType, XeMATRIX);
		_PluginInfoDialogW = XeDialog_New(XeDIALOG_INFORMATION, "Plugin info", E_TopShellW,  Args, ArgCnt);if(_PluginInfoDialogW == NULL) return;
		XeAddCallback(_PluginInfoDialogW, XeNWMCallback, _CB_PluginInfo, (EPointer)XeCR_CANCEL);

		XeWidget  LTopMatrixW = XeDialog_GetChild(_PluginInfoDialogW, XeDIALOG_WORK_AREA);

/*
  EXeStart;
  EXeSetArg(XeNMarginSizeX, 2);EXeSetArg(XeNMarginSizeY, 2);
  Xe_SetValues(LTopMatrixW,  Args, ArgCnt);
*/

		EXeStart;
//  EXeSetArg(XeNShadowThickness, 1);EXeSetArg(XeNShadowType, XeShadowIN);
		EXeSetArg(XeNMarginSizeX, 0);EXeSetArg(XeNMarginSizeY, 7);
		EXeSetArg(XeNMarginRight, 7);
		EXeSetArg(XeNResizableX, FALSE);EXeSetArg(XeNAlignmentX, XeAlignBEGINNING);
		EXeSetArg(XeNResizableY, FALSE);EXeSetArg(XeNAlignmentY, XeAlignBEGINNING);

		if(LXeStr)
		{
			EXeSetArg(XeNLabelString, LXeStr);
		}
		_PluginInfoLabelW = XeWidget_ManagedNew("", XeLabelWidget_class, LTopMatrixW,  Args, ArgCnt);
	}
	else
	{
		if(LXeStr)
		{
			EXeStart;
			EXeSetArg(XeNLabelString, LXeStr);
			Xe_SetValues(_PluginInfoLabelW,  Args, ArgCnt);
		}
	}

	_InfoPlugin = LPluginM;

	if(LXeStr) XeString_Free(LXeStr);
	XeShell_Raise(_PluginInfoDialogW);
}


//========================================
// Refresh Plugin manager GUI
//========================================
void E3dp_RefreshPluginList(void)
{
	int   LNumOfAccessiblePlugins = E_Plugins.Count;
	EArg  Args[64];int  ArgCnt;

	if(LNumOfAccessiblePlugins == 0) return;
	if(_AccessiblePluginsM == NULL)
	{
		ENewN(LNumOfAccessiblePlugins, _AccessiblePluginsM);

		if(_AccessiblePluginsM == NULL) return;

		_MaxNumOfAccessiblePluginsM = LNumOfAccessiblePlugins;
		EPluginM**	LAccessiblePlugins = _AccessiblePluginsM;
		int  LI = 0;for(;LI < LNumOfAccessiblePlugins;LI++)
		{
			ENew(LAccessiblePlugins[LI]);
			if(LAccessiblePlugins[LI])
			{
				EPluginM*  LAccessiblePlugin = LAccessiblePlugins[LI];E3dp_InitPluginMRec(LAccessiblePlugin);
			}
		}
	}

	if(LNumOfAccessiblePlugins > _MaxNumOfAccessiblePluginsM)
	{
		EResizeNC(EPluginM*, LNumOfAccessiblePlugins,  _AccessiblePluginsM, _MaxNumOfAccessiblePluginsM);
		if(_AccessiblePluginsM)
		{
			EPluginM**  LAccessiblePlugins = _AccessiblePluginsM;
			int  LI = _MaxNumOfAccessiblePluginsM;for(;LI < LNumOfAccessiblePlugins;LI++)
			{
				ENew(LAccessiblePlugins[LI]);
				if(LAccessiblePlugins[LI])
				{
					EPluginM*  LAccessiblePlugin = LAccessiblePlugins[LI];E3dp_InitPluginMRec(LAccessiblePlugin);
				}
			}
		}
	}

	if(_AccessiblePluginsM)
	{
		if(E_Plugins.Count <= _MaxNumOfAccessiblePluginsM)  // Get the loaded plugins first
		{
			EcRGBAiColor*  LForegroundColorP = &Xe_ForegroundRGBAiColor;
			EcRGBAiColor*  LBackgroundColorP = &Xe_ListBackgroundRGBAiColor;

			EPluginM**          LAccessiblePlugins = _AccessiblePluginsM;
			const XeCoordinate  LSpacingLeft = 0, LSpacingX = 8, LSpacingRight = 0;
//const int   LSpacingX = 200;

			EXeStart;
			EXeSetArg(XeNMarginSizeX, 0);EXeSetArg(XeNSpacingLeft, LSpacingLeft);EXeSetArg(XeNSpacingRight, LSpacingRight);
			EXeSetArg(XeNMarginSizeY, 0);
			EXeSetArg(XeNSpacingX, LSpacingX);EXeSetArg(XeNSpacingY, 1);
			EXeSetArg(XeNShadowThickness, 0);
			EXeSetArg(XeNOrientation, XeHORIZONTAL);
			EXeSetArg(XeNColumns, _NColumns);

#if XeDebugTOGGLEBUTTON
EXeSetArg(XeNBackgroundColorPtr, &Xe_CyanRGBAiColor);
#else
			EXeSetArg(XeNBackgroundColorPtr, LBackgroundColorP);
#endif
			EXeSetArg(XeNWidgetWithHeader, _PluginsScrolledWindowW);  // Synchronize the ScrolledWindow's header to this Matrix
			XeWidget  LRootFolderMatrixW = XeWidget_ManagedNew("PluginMatrixW-Root  ", XeMatrixWidget_class, _PluginsTopMatrixW,  Args, ArgCnt);

			XeScrolledWindow_ColumnHeaderAddDrivingMatrix(_PluginsScrolledWindowW, LRootFolderMatrixW);
					EXeSetArg(XeNForegroundColorPtr, LForegroundColorP);
					EXeSetArg(XeNBackgroundColorPtr, LBackgroundColorP);

			int    LRowSizeY = 2, LSpacingY = 0, LIndent = 0;
			EBool  LSetScrollStep = FALSE;

			int  LI = 0;for(;LI < E_Plugins.Count;LI++)
			{
				EPluginM*  LAccessiblePlugin = LAccessiblePlugins[LI];
				EPlugin*   LPlugin = E_Plugins.Items + LI;

				LAccessiblePlugin->Plugin = LPlugin;

				if(LPlugin->DLHandle) LAccessiblePlugin->Loaded = TRUE;
				else LAccessiblePlugin->Loaded = FALSE;

				if(LAccessiblePlugin->LabelW == NULL)
				{
					XeWidget  LW, LMatrixW = NULL;

// Check if the plugin name has a folder defined (folder/name format)
//
//printf("%s() %s:%d  [%s]\n", __FUNCTION__, __FILE__, __LINE__, LAccessiblePlugin->Plugin->Name);fflush(stdout);
					char  LFolderName[MAXPATHLEN];if(EStr_GetPathName(LAccessiblePlugin->Plugin->Name,  LFolderName, MAXPATHLEN))
					{
						const size_t  LL = strlen(LFolderName);LFolderName[LL - 1] = 0;

//printf("%s() %s:%d   [%s]/\n", __FUNCTION__, __FILE__, __LINE__, LFolderName);fflush(stdout);

						LIndent = Xe_ArrowRightImage ? Xe_ArrowRightImage->Size.X + 6 : 22;

						int  LFI = 0;XeDrawer*  LFolder = _Folders;for(;LFI < _NumOfFolders;LFI++, LFolder++)
						{
							if(EStr_Equal(LFolder->Name, LFolderName))
							{
								LMatrixW = LFolder->DrawerW;
								break;
							}
						}

						if(LFI == _NumOfFolders)
						{
							if(_NumOfFolders < 64)
							{
								LFolder = _Folders + LFI;

								strcpy(LFolder->Name, LFolderName);

								EXeStart;
								EXeSetArg(XeNSpacingLeft, 4);
								EXeSetArg(XeNMarginSizeX, 0);
								EXeSetArg(XeNMarginSizeY, 0);EXeSetArg(XeNMarginTop, 4);EXeSetArg(XeNMarginBottom, 0);
								EXeSetArg(XeNShadowThickness, 0);
								EXeSetArg(XeNFontList, Xe_LabelFontList);
								EXeSetArg(XeNLabelAlignmentX, XeAlignBEGINNING);
								EXeSetArg(XeNLabelType, XeIMAGE_STRING_HORIZONTAL);

								EXeSetArg(XeNForegroundColorPtr, LForegroundColorP);
								EXeSetArg(XeNBackgroundColorPtr, LBackgroundColorP);
/*
								EXeSetArg(XeNForegroundColorPtr, &Xe_ForegroundRGBAiColor);
								EXeSetArg(XeNActiveColorPtr, LBackgroundColorP);
								EXeSetArg(XeNArmColorPtr, LBackgroundColorP);
*/
								EXeSetImages2(Xe_ArrowRightImage);

								EXeSetArg(XeNBackgroundGradient, FALSE);
								LFolder->OpenCloseButtonW = LW = XeWidget_ManagedNew(LFolderName, XePushButton_class, _PluginsTopMatrixW,  Args, ArgCnt);
								XeAddCallback(LW, XeNActivateCallback, XeDrawerCB_OpenClose, (EPointer)LFolder);

								{
									char  LTmpStr[MAXPATHLEN + 16];sprintf(LTmpStr, "PluginMatrixW-%s", LFolderName);
									EXeStart;
									EXeSetArg(XeNMarginSizeX, 0);EXeSetArg(XeNSpacingLeft, LSpacingLeft);EXeSetArg(XeNSpacingRight, LSpacingRight);
									EXeSetArg(XeNMarginSizeY, 0);
									EXeSetArg(XeNSpacingX, LSpacingX);EXeSetArg(XeNSpacingY, 1);
									EXeSetArg(XeNShadowThickness, 0);
									EXeSetArg(XeNOrientation, XeHORIZONTAL);
									EXeSetArg(XeNColumns, _NColumns);
									EXeSetArg(XeNBackgroundColorPtr, LBackgroundColorP);
//EXeSetArg(XeNBackgroundColorPtr, &Xe_ButtonRGBAiColor);
									EXeSetArg(XeNWidgetWithHeader, _PluginsScrolledWindowW);  // Synchronize the ScrolledWindow's header to this Matrix
									LFolder->DrawerW = LMatrixW = XeWidget_New(LTmpStr, XeMatrixWidget_class, _PluginsTopMatrixW,  Args, ArgCnt);

									XeScrolledWindow_ColumnHeaderAddDrivingMatrix(_PluginsScrolledWindowW, LMatrixW);
								}

								_NumOfFolders += 1;
							}
						}
					}
					else
					{
// No folder specified, put this plugin in the root folder Matrix
//
						LMatrixW = LRootFolderMatrixW;
						LIndent = 6;
					}

					const char*  LFileName = EStr_GetFileName(LAccessiblePlugin->Plugin->Name);

// Name Label
//
					EXeStart;
					EXeSetArg(XeNMarginSizeY, 0);
					EXeSetArg(XeNSpacingLeft, LIndent);
					EXeSetArg(XeNLabelAlignmentX, XeAlignBEGINNING);
					EXeSetArg(XeNForegroundColorPtr, LForegroundColorP);
					EXeSetArg(XeNBackgroundColorPtr, LBackgroundColorP);

// Keep the Label resizable by the Matrix and align the String to the left, so as folders are opened and closed, the buttons will still line up.
// So, this is commented out...
//				EXeSetArg(XeNResizableX, FALSE);EXeSetArg(XeNAlignmentX, XeAlignBEGINNING);

					EXeSetArg(XeNResizableY, FALSE);
					{
						XeString  LXeStr = XeString_SimpleNew(LFileName);
						EXeSetArg(XeNLabelString, LXeStr);
						LAccessiblePlugin->LabelW = XeWidget_ManagedNew("", XeLabelWidget_class, LMatrixW,  Args, ArgCnt);
						XeString_Free(LXeStr);
					}

#if XeDebugTOGGLEBUTTON
					const int  LIndicatorSize = 36;
#else
					const int  LIndicatorSize = 20;
#endif

// "Load" button
//
					EXeStart;
					EXeSetArg(XeNMarginSizeY, 0);
					EXeSetArg(XeNResizableX, FALSE);
					EXeSetArg(XeNResizableY, FALSE);
					EXeSetArg(XeNIndicatorSize, LIndicatorSize);
					EXeSetArg(XeNSet, LAccessiblePlugin->Loaded);
					XeToolTip8("Load / unload plugin");
					LAccessiblePlugin->LoadedBW = LW = XeWidget_ManagedNew("", XeToggleButton_class, LMatrixW,  Args, ArgCnt);
					XeAddCallback(LW, XeNValueChangedCallback, _CBPluginManager_LoadUnload, (EPointer)LAccessiblePlugin);

// "Auto-load" button
//
					EXeStart;
					EXeSetArg(XeNMarginSizeY, 0);
					EXeSetArg(XeNIndicatorSize, LIndicatorSize);
					EXeSetArg(XeNResizableX, FALSE);
					EXeSetArg(XeNResizableY, FALSE);
					EXeSetArg(XeNSet, LPlugin->AutoReload);
					XeToolTip8("Automatically (re) load this plugin, if it changes.");
					LAccessiblePlugin->AutoLoadBW = LW = XeWidget_ManagedNew("Auto", XeToggleButton_class, LMatrixW,  Args, ArgCnt);
					XeAddCallback(LW, XeNValueChangedCallback, _CBPluginManager_AutoLoad, (EPointer)LAccessiblePlugin);

// "Info" button
//
					EXeStart;
					EXeSetArg(XeNMarginSizeX, 4);
					EXeSetArg(XeNMarginSizeY, 0);EXeSetArg(XeNMarginTop, 0);EXeSetArg(XeNMarginBottom, 0);
					EXeSetArg(XeNResizableX, FALSE);
//EXeSetArg(XeNAlignmentX, XeAlignCENTER);
					EXeSetArg(XeNResizableY, FALSE);
					XeToolTip8("Show details about this plugin.");
					LAccessiblePlugin->InfoBW = LW = XeWidget_ManagedNew("i", XePushButton_class, LMatrixW,  Args, ArgCnt);
					XeAddCallback(LW, XeNActivateCallback, _CB_PluginManagerInfo, (EPointer)LAccessiblePlugin);
					const int  LTRowSizeY = XeMatrix_RowSizeY(LMatrixW, 0);
					if(LRowSizeY < LTRowSizeY) LRowSizeY = LTRowSizeY;
					int  LTSpacingY = 0;Xe_GetValuesVa(LMatrixW,  XeNSpacingY, &LTSpacingY,  NULL);
					if(LSpacingY < LTSpacingY) LSpacingY = LTSpacingY;
					LSetScrollStep = TRUE;
				}
			}

			if(LSetScrollStep)
			{
				Xe_SetValuesVa(_PluginsVScrollbarW,
				 XeNIncrement, LRowSizeY + LSpacingY,
				 XeNSmoothScrollSteps, 8,
				 XeNScrollWheelIncrement, (LRowSizeY + LSpacingY),
				 NULL);
			}
		}
	}
}


//========================================
// Pop up plugin manager
//========================================
void Xe_PopUpPluginManager(const char* PDialogTitle)
{
	if(_PluginManagerDialogW == NULL)
	{
		EArg  Args[64];int  ArgCnt;

		EXeStart;
//		EXeSetArg(XeNSelfResizePolicyX, XeGROW);EXeSetArg(XeNSelfResizePolicyY, 0);
		EXeSetArg(XeNButtonsStretch, FALSE);
		EXeSetArg(XeNCreateButtons, FALSE);
		EXeSetArg(XeNWorkAreaType, XeMATRIX);
		EXeSetArg(XeNMinSizeX, 360);EXeSetArg(XeNMinSizeY, 240);
		EXeSetArg(XeNWMDecorations, XeWMDecorCLOSE|XeWMDecorBORDER|XeWMDecorRESIZEH|XeWMDecorTITLE|XeWMDecorMINIMIZE);
		EXeSetArg(XeNTitle, PDialogTitle);EXeSetArg(XeNIconName, "Plugins");
		_PluginManagerDialogW = XeDialog_New(XeDIALOG_TEMPLATE, PDialogTitle, E_TopShellW,  Args, ArgCnt);if(_PluginManagerDialogW == NULL) return;
		XeAddCallback(_PluginManagerDialogW, XeNWMCallback, EguiCB_PluginManager, (EPointer)XeCR_CANCEL);

		XeWidget  LTopMatrixW = XeDialog_GetChild(_PluginManagerDialogW, XeDIALOG_WORK_AREA);

		EXeStart;
		EXeSetArg(XeNOrientation, XeVERTICAL);
		EXeSetArg(XeNMarginSizeX, 0);EXeSetArg(XeNMarginSizeY, 0);
		EXeSetArg(XeNSpacingY, 3);
		Xe_SetValues(LTopMatrixW,  Args, ArgCnt);

//	const EcRGBAiColor*  LBackgroundColorP = &Xe_BackgroundRGBAiColor;
		const EcRGBAiColor*  LBackgroundColorP = &Xe_ListBackgroundRGBAiColor;

		EXeStart;
//		EXeSetArg(XeNSelfResizePolicyX, XeGROW);EXeSetArg(XeNSelfResizePolicyY, 0);
		EXeSetArg(XeNBackgroundColorPtr, LBackgroundColorP);
//EXeSetArg(XeNBackgroundColorPtr, &Xe_CyanRGBAiColor);
		EXeSetArg(XeNScrollBarTroughColorPtr, &Xe_ListBackgroundRGBAiColor);
		EXeSetArg(XeNShadowThickness, 2);EXeSetArg(XeNShadowType, XeShadowIN);
		EXeSetArg(XeNWorkAreaShadowThickness, 0);
		EXeSetArg(XeNScrollingPolicy, XeAUTOMATIC);
		EXeSetArg(XeNScrollBarDisplayPolicyX, XeAS_NEEDED);EXeSetArg(XeNScrollBarDisplayPolicyY, XeAS_NEEDED);
		EXeSetArg(XeNSpacing, 0);
		_PluginsClipWindowW = XeScrolledWindow_New(LTopMatrixW, "PluginsScrW",  Args, ArgCnt);
		_PluginsScrolledWindowW = Xe_Parent(_PluginsClipWindowW);
		Xe_GetValuesVa(_PluginsScrolledWindowW,  XeNScrollBarY, &_PluginsVScrollbarW,  NULL);

		EXeStart;
		EXeSetArg(XeNSelfResizePolicyX, XeSHRINK|XeGROW);EXeSetArg(XeNSelfResizePolicyY, 0);
		Xe_SetValues(_PluginsScrolledWindowW,  Args, ArgCnt);

		{
			EXeStart;
			EXeSetArg(XeNEditable, FALSE);
			EXeSetArg(XeNSortDirectionArrowOn, FALSE);
			XeScrolledWindow_ColumnHeaderAddButton("Name", _PluginsScrolledWindowW,  Args, ArgCnt);

			EXeStart;
			EXeSetArg(XeNEditable, FALSE);
			EXeSetArg(XeNSortDirectionArrowOn, FALSE);
			XeScrolledWindow_ColumnHeaderAddButton("Load", _PluginsScrolledWindowW,  Args, ArgCnt);

			EXeStart;
			EXeSetArg(XeNEditable, FALSE);
			EXeSetArg(XeNSortDirectionArrowOn, FALSE);
			XeScrolledWindow_ColumnHeaderAddButton("Auto", _PluginsScrolledWindowW,  Args, ArgCnt);

			EXeStart;
			EXeSetArg(XeNEditable, FALSE);
			EXeSetArg(XeNSortDirectionArrowOn, FALSE);
			XeScrolledWindow_ColumnHeaderAddButton("Info", _PluginsScrolledWindowW,  Args, ArgCnt);

			EXeStart;
			EXeSetArg(XeNSensitive, FALSE);
			EXeSetArg(XeNSortDirectionArrowOn, FALSE);
			XeScrolledWindow_ColumnHeaderAddButton("", _PluginsScrolledWindowW,  Args, ArgCnt);
		}


		EXeStart;
		EXeSetArg(XeNMarginSizeX, 0);EXeSetArg(XeNMarginSizeY, 2);
		EXeSetArg(XeNSpacingY, 2);
		EXeSetArg(XeNShadowThickness, 0);
		EXeSetArg(XeNOrientation, XeVERTICAL);
		EXeSetArg(XeNBackgroundColorPtr, LBackgroundColorP);
//EXeSetArg(XeNBackgroundColorPtr, &Xe_CyanRGBAiColor);
		_PluginsTopMatrixW = XeWidget_ManagedNew("PluginsTopMatrixW", XeMatrixWidget_class, _PluginsClipWindowW,  Args, ArgCnt);

		EXeStart;
//EXeSetArg(XeNBackgroundColorPtr, &Xe_CyanRGBAiColor);
		Xe_SetValues(_PluginsClipWindowW,  Args, ArgCnt);

		Xe_GeometryUpdateDisable(_PluginsTopMatrixW);
		E3dp_RefreshPluginList();
		Xe_GeometryUpdateEnable(_PluginsTopMatrixW, XeChgLAYOUT|XeChgCONFIGURECHILDREN|XeChgREDRAW);
		XeWidget_Manage(_PluginsScrolledWindowW);
		XeShell_Raise(_PluginManagerDialogW);

/*
		Xe_GeometryUpdateDisable(_PluginsTopMatrixW);
		E3dp_RefreshPluginList();
		Xe_GeometryUpdateEnable(_PluginsTopMatrixW, XeChgLAYOUT|XeChgCONFIGURECHILDREN|XeChgREDRAW);
*/

		EXeStart;
		EXeSetArg(XeNSelfResizePolicyY, 0);
//EXeSetArg(XeNBackgroundColorPtr, &Xe_CyanRGBAiColor);
		Xe_SetValues(_PluginsScrolledWindowW,  Args, ArgCnt);
	}
	else
	{
		Xe_GeometryUpdateDisable(_PluginsTopMatrixW);
		E3dp_RefreshPluginList();
		Xe_GeometryUpdateEnable(_PluginsTopMatrixW, XeChgLAYOUT|XeChgCONFIGURECHILDREN|XeChgREDRAW);

		XeShell_Raise(_PluginManagerDialogW);
	}
}
