Hi sir,
I just moved to another method to add ribbons, panels, rows, and buttons. I have done some code but what I need now is how to handle the user's modifications. I mean I don't want it to be changed by CUI editor. If edited then it will run and will be restored. And now it is unloading and loading the code multiple times at once. Means there are many events which is doing it. Any help on this would be greatly appreciated. Thank you!
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Customization;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Application = Autodesk.AutoCAD.ApplicationServices.Core.Application;
using Exception = Autodesk.AutoCAD.Runtime.Exception;
public class AddRibbon : IExtensionApplication
{
#region Global Variables
#pragma warning disable IDE1006
private static Editor ed { get; set; }
public bool isCuiLoaded = false;
private FileSystemWatcher _cuiFileWatcher;
#pragma warning restore IDE1006
#endregion
public void Initialize()
{
Application.Idle += OnIdle;
Application.DocumentManager.DocumentActivated += OnDocActivated;
// Setup CUI file watcher
var cuiFileName = "CADTools.cuix";
var cuiPath = Path.GetDirectoryName(Application.GetSystemVariable("MENUNAME") + ".cuix");
var cuiFilePath = Path.Combine(cuiPath, cuiFileName);
StartCuiFileWatcher(cuiFilePath);
}
private void OnIdle(object sender, EventArgs e)
{
CheckAndCreateCuiFile();
Application.Idle -= OnIdle;
}
private void OnDocActivated(object sender, DocumentCollectionEventArgs e)
{
if (Application.DocumentManager.Count != 0)
{
Application.DocumentManager.DocumentActivated -= OnDocActivated;
SafeExecuteWithSystemVariables(() =>
{
LoadCui();
});
}
}
public void Terminate()
{
Application.Idle -= OnIdle;
Application.DocumentManager.DocumentActivated -= OnDocActivated;
StopCuiFileWatcher();
}
private void StartCuiFileWatcher(string cuiFilePath)
{
_cuiFileWatcher?.Dispose();
var cuiDirectory = Path.GetDirectoryName(cuiFilePath);
var cuiFileName = Path.GetFileName(cuiFilePath);
_cuiFileWatcher = new FileSystemWatcher
{
Path = cuiDirectory,
Filter = cuiFileName,
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size,
EnableRaisingEvents = true
};
_cuiFileWatcher.Changed += OnCuiFileChanged;
}
private void StopCuiFileWatcher()
{
if (_cuiFileWatcher != null)
{
_cuiFileWatcher.Changed -= OnCuiFileChanged;
_cuiFileWatcher.Dispose();
_cuiFileWatcher = null;
}
}
private void OnCuiFileChanged(object sender, FileSystemEventArgs e)
{
try
{
SafeExecuteWithSystemVariables(() =>
{
ReloadCui(e.FullPath);
});
ed?.WriteMessage($"\nCUI file '{e.FullPath}' was modified and reloaded.");
}
catch (Exception ex)
{
ed?.WriteMessage($"\nError reloading CUI file: {ex.Message}");
}
}
private static void ReloadCui(string cui)
{
var cuiName = Path.GetFileNameWithoutExtension(cui);
ed?.Document.SendStringToExecute("_.CUIUNLOAD " + cuiName + " ", false, false, false);
ed?.Document.SendStringToExecute("_.CUILOAD \"" + cui + "\" ", false, false, false);
}
[CommandMethod("AddRibbon")]
public void Loadcuicommand()
{
SafeExecuteWithSystemVariables(() =>
{
LoadCui();
});
}
private void LoadCui()
{
ed = Application.DocumentManager.MdiActiveDocument?.Editor;
var myCuiFileName = "CADTools.cuix";
var cuiPath = Path.GetDirectoryName(Application.GetSystemVariable("MENUNAME") + ".cuix");
var myCuiFilePath = Path.Combine(cuiPath, myCuiFileName);
var wsCurrent = (string)Application.GetSystemVariable("WSCURRENT");
var mainCui = (string)Application.GetSystemVariable("MENUNAME") + ".cuix";
var mainCs = new CustomizationSection(mainCui);
var pcfc = mainCs.PartialCuiFiles;
CheckAndCreateCuiFile();
var myCs = new CustomizationSection(myCuiFilePath);
// Add ribbon tabs
var ribTabCol = new[]
{
AddOrGetRibbonTab(myCs, "CAD Tools"),
};
var validTabs = ribTabCol.Select(tab => tab.Name).ToArray();
RemoveUnusedTabs(myCs, validTabs);
// Add tab panels
var tabName = "CADTools";
var cadToolsPanels = new[]
{
(tabName, "CAD Tools"),
};
RemoveUnusedPanels(myCs, tabName, cadToolsPanels);
AddOrGetRibbonPanelsToTabs(myCs, cadToolsPanels, ribTabCol);
AddButtons.AddSimpleButton(myCs, "CADTools", ed);
myCs.Save();
ed?.WriteMessage("\nRibbon setup completed.");
}
private void CheckAndCreateCuiFile()
{
var myCuiFileName = "CADTools.cuix";
var cuiPath = Path.GetDirectoryName(Application.GetSystemVariable("MENUNAME") + ".cuix");
var myCuiFilePath = Path.Combine(cuiPath, myCuiFileName);
if (!File.Exists(myCuiFilePath))
{
var pcs = new CustomizationSection();
pcs.SaveAs(myCuiFilePath);
}
}
private static RibbonTabSource AddOrGetRibbonTab(CustomizationSection cs, string tabText)
{
var ribRoot = cs.MenuGroup.RibbonRoot;
var tabName = tabText.Replace(" ", "");
var tabId = $"{tabName}_TabId";
var tab = ribRoot.FindTab(tabId);
if (tab == null)
{
tab = new RibbonTabSource(ribRoot)
{
Name = tabName,
Text = tabText,
ElementID = tabId,
Id = tabId
};
ribRoot.RibbonTabSources.Add(tab);
}
return tab;
}
private static void RemoveUnusedTabs(CustomizationSection cs, string[] validTabs)
{
var ribRoot = cs.MenuGroup.RibbonRoot;
// Get all tabs in RibbonTabSources
var tabsToDelete = new List<RibbonTabSource>();
foreach (RibbonTabSource tab in ribRoot.RibbonTabSources)
{
// Check if the tab is not in the valid list
if (!validTabs.Contains(tab.Name))
{
tabsToDelete.Add(tab);
}
}
// Remove the tabs that are not in the valid list
foreach (var tab in tabsToDelete)
{
ribRoot.RibbonTabSources.Remove(tab);
}
}
private static void AddOrGetRibbonPanelsToTabs(CustomizationSection cs, (string tabName, string panelText)[] panels, RibbonTabSource[] ribTabCol)
{
var ribRoot = cs.MenuGroup.RibbonRoot;
foreach (var (tabName, panelText) in panels)
{
// Find the tab that matches the tabName
RibbonTabSource tab = ribTabCol.FirstOrDefault(t => t.Name == tabName);
if (tab != null)
{
var panelName = panelText.Replace(" ", "");
var panelId = $"{panelName}_PanelId";
// Check if the panel already exists
RibbonPanelSource existingPanel = null;
foreach (RibbonPanelSource panel in ribRoot.RibbonPanelSources)
{
if (panel.ElementID == panelId || panel.Name == panelName)
{
existingPanel = panel;
break;
}
}
if (existingPanel != null)
{
// Check if the panel is already referenced in the tab
bool isReferenced = false;
foreach (var item in tab.Items)
{
if (item is RibbonPanelSourceReference refItem && refItem.PanelId == existingPanel.ElementID)
{
isReferenced = true;
break;
}
}
if (!isReferenced)
{
// Add the panel reference to the tab
var panelRef = new RibbonPanelSourceReference(tab)
{
PanelId = existingPanel.ElementID
};
tab.Items.Add(panelRef);
}
ed?.WriteMessage($"Panel '{panelText}' already exists in tab '{tabName}'.");
}
else
{
// Create the new panel if not found
var newPanel = new RibbonPanelSource(ribRoot)
{
Name = panelName,
Text = panelText,
ElementID = panelId,
Id = panelId
};
ribRoot.RibbonPanelSources.Add(newPanel);
// Add the panel reference to the tab
var newPanelRef = new RibbonPanelSourceReference(tab)
{
PanelId = newPanel.ElementID
};
tab.Items.Add(newPanelRef);
ed?.WriteMessage($"Created new panel: {panelText} in tab '{tabName}'");
}
}
else
{
ed?.WriteMessage($"Tab '{tabName}' not found, skipping panel '{panelText}'.");
}
}
}
private static void RemoveUnusedPanels(CustomizationSection cs, string tabName, (string tabName, string panelText)[] validPanels)
{
var ribRoot = cs.MenuGroup.RibbonRoot;
// Create a dictionary for easy lookup of valid panel names by tab name
var validPanelsDict = validPanels
.GroupBy(panel => panel.tabName)
.ToDictionary(g => g.Key, g => new HashSet<string>(g.Select(p => p.panelText.Replace(" ", "")), StringComparer.OrdinalIgnoreCase));
// Find the RibbonTabSource based on the specified tabName
var formattedTabName = tabName.Replace(" ", "");
RibbonTabSource tab = null;
foreach (RibbonTabSource t in ribRoot.RibbonTabSources)
{
if (string.Equals(t.Name, formattedTabName, StringComparison.OrdinalIgnoreCase))
{
tab = t;
break;
}
}
if (tab == null)
{
ed?.WriteMessage($"\nTab '{tabName}' not found.");
return;
}
// Check if the tab has valid panels defined
if (!validPanelsDict.ContainsKey(tab.Name))
{
ed?.WriteMessage($"\nNo valid panels specified for tab '{tabName}'.");
return;
}
// Get the list of valid panel IDs for the tab
var validPanelIds = new HashSet<string>(
validPanelsDict[tab.Name].Select(panelText => $"{panelText.Replace(" ", "")}_PanelId"),
StringComparer.OrdinalIgnoreCase
);
// Collect unused panels
var panelsToDelete = new List<RibbonPanelSource>();
var panelReferencesToDelete = new List<RibbonPanelSourceReference>();
// Remove panel references from the tab
foreach (var item in tab.Items.OfType<RibbonPanelSourceReference>())
{
if (!validPanelIds.Contains(item.PanelId))
{
panelReferencesToDelete.Add(item);
// Also find the panel source for removal
var panelSource = ribRoot.FindPanel(item.PanelId);
if (panelSource != null)
{
panelsToDelete.Add(panelSource);
}
}
}
foreach (var panelRef in panelReferencesToDelete)
{
tab.Items.Remove(panelRef);
ed?.WriteMessage($"\nRemoved unused panel reference '{panelRef.PanelId}' from tab '{tabName}'.");
}
ed?.WriteMessage($"\nCleanup of unused panels in tab '{tabName}' completed.");
}
private void SafeExecuteWithSystemVariables(Action action)
{
object cmdEcho = Application.GetSystemVariable("CMDECHO");
object fileDia = Application.GetSystemVariable("FILEDIA");
try
{
Application.DocumentManager.MdiActiveDocument.SendStringToExecute("_.filedia " + 0 + " ", false, false, false);
Application.DocumentManager.MdiActiveDocument.SendStringToExecute("_.cmdecho " + 0 + " ", false, false, false);
action.Invoke();
}
catch (Exception ex)
{
ed?.WriteMessage($"\nError: {ex.Message}\n");
}
finally
{
Application.DocumentManager.MdiActiveDocument.SendStringToExecute("_.filedia " + fileDia + " ", false, false, false);
Application.DocumentManager.MdiActiveDocument.SendStringToExecute("_.cmdecho " + cmdEcho + " ", false, false, false);
}
}
}
class AddButtons
{
public static void AddSimpleButton(CustomizationSection cs, string panelName, Editor ed)
{
try
{
if (cs == null) return;
RibbonPanelSource panelsrc=GetRibbonPanel(cs, panelName);
if (panelsrc== null) return;
MacroGroup macGroup;
if (cs.MenuGroup.MacroGroups.Count == 0)
{
macGroup = new MacroGroup(cs.MenuGroupName, cs.MenuGroup);
}
else
{
macGroup = cs.MenuGroup.MacroGroups[0];
}
panelSrc.Items.Clear();
RibbonRow ribbonRow1 = new RibbonRow(panelSrc);
if (panelSrc.Items.Count == 0)
{
panelSrc.Items.Add(ribbonRow1);
}
RibbonCommandButton button1 = new RibbonCommandButton(ribbonRow1)
{
Text = "Extract\nCross Sections"
};
MenuMacro menuMac1 = macGroup.CreateMenuMacro("Button1", "^C^COO", "Button1_Tag", "Button1_Help",
MacroType.Any, "RCDATA_16_EXPORT_FILE", "RCDATA_16_EXPORT_FILE", "Button1_Label_Id");
button1.MacroID = menuMac1.ElementID;
button1.ButtonStyle = RibbonButtonStyle.LargeWithText;
button1.KeyTip = "Button1 Key Tip";
button1.TooltipTitle = "Button1 Tooltip Title!";
ribbonRow1.Items.Add(button1);
RibbonRowPanel subPanel1 = new RibbonRowPanel(ribbonRow1);
ribbonRow1.Items.Add(subPanel1);
RibbonRow ribbonRow2 = new RibbonRow(subPanel1);
subPanel1.Items.Add(ribbonRow2);
RibbonCommandButton button2 = new RibbonCommandButton(ribbonRow2)
{
Text = "Export XS into PDF Files"
};
MenuMacro menuMac2 = macGroup.CreateMenuMacro("Button2", "^C^CPTP", "Button2_Tag", "Button2_Help",
MacroType.Any, "RCDATA_16_EXPORT_FILE", "RCDATA_16_EXPORT_FILE", "Button2_Label_Id");
button2.MacroID = menuMac2.ElementID;
button2.ButtonStyle = RibbonButtonStyle.SmallWithText;
button2.KeyTip = "Button2 Key Tip";
button2.TooltipTitle = "Button2 Tooltip Title!";
ribbonRow2.Items.Add(button2);
RibbonRow ribbonRow3 = new RibbonRow(subPanel1);
subPanel1.Items.Add(ribbonRow3);
RibbonCommandButton button3 = new RibbonCommandButton(ribbonRow3)
{
Text = "Export XS Data into CSV"
};
MenuMacro menuMac3 = macGroup.CreateMenuMacro("Button3", "^C^CFF", "Button3_Tag", "Button3_Help",
MacroType.Any, "RCDATA_16_EXPORT_FILE", "RCDATA_16_EXPORT_FILE", "Button3_Label_Id");
button3.MacroID = menuMac3.ElementID;
button3.ButtonStyle = RibbonButtonStyle.SmallWithText;
button3.KeyTip = "Button3 Key Tip";
button3.TooltipTitle = "Button3 Tooltip Title!";
ribbonRow3.Items.Add(button3);
cs.Save();
}
catch (Exception ex)
{
ed.WriteMessage($"\n{ex.Message}\n{ex.StackTrace}");
}
}
private static RibbonPanelSource GetRibbonPanel(CustomizationSection cs, string panelName)
{
foreach (RibbonPanelSource panel in cs.MenuGroup.RibbonRoot.RibbonPanelSources)
{
if (panel.Name == panelName)
{
return panel;
}
}
return null;
}
}