// // (C) Copyright 2003-2019 by Autodesk, Inc. All rights reserved. // // Permission to use, copy, modify, and distribute this software in // object code form for any purpose and without fee is hereby granted // provided that the above copyright notice appears in all copies and // that both that copyright notice and the limited warranty and // restricted rights notice below appear in all supporting // documentation. // // AUTODESK PROVIDES THIS PROGRAM 'AS IS' AND WITH ALL ITS FAULTS. // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE // UNINTERRUPTED OR ERROR FREE. // // Use, duplication, or disclosure by the U.S. Government is subject to // restrictions set forth in FAR 52.227-19 (Commercial Computer // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. using System; using System.IO; using System.Collections.Generic; using System.Reflection; using System.Windows.Media.Imaging; using Autodesk.Revit.UI; using Autodesk.Revit.DB; using Autodesk.Revit.UI.Events; namespace Revit.SDK.Samples.SinePlotter.CS { /// /// Implements the Revit add-in interface IExternalApplication /// [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)] [Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)] public class Application : IExternalApplication { private string assemblyPath; private string assemblyName; private string imageFolder; private static double periodVal = 0.2; private static double cyclesVal = 10; private static double amplitudeVal = 3; private static double partitionsVal = 3; private static ComboBox prismComboBox; private TextBox periodBox; private TextBox cyclesBox; private TextBox amplitudeBox; private TextBox partitionsBox; #region IExternalApplication Members /// /// Implements the OnShutdown event /// /// /// Indicates if the application completes its work successfully. public Result OnShutdown(UIControlledApplication application) { return Result.Succeeded; } /// /// Implements the OnStartup event /// /// /// Indicates if the application completes its work successfully. public Result OnStartup(UIControlledApplication application) { assemblyPath = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); assemblyName = Assembly.GetExecutingAssembly().GetName().Name + ".dll"; imageFolder = GetProjectDirectory() + "/Resources/"; //add a panel to go on the Add-In tab RibbonPanel panel = application.CreateRibbonPanel("ArrayPrismsOnASineCurve"); //add panel with text fields for user input for period, amplitude and cycles of sine curve AddCurvePropertiesTextFields(panel); //add panel with text field for user input for number of partitions along the curve AddPartitionsTextField(panel); panel.AddSeparator(); //add drop down menu for type of prism selection AddPrismComboBox(panel); panel.AddSeparator(); //add RUN button AddRunButton(panel); return Result.Succeeded; } /// /// Gets the name of the currently selected family symbol. /// /// A string representing the name of the currently selected family symbol public static String GetFamilySymbolName() { return prismComboBox.Current.Name; } /// /// Gets the value corresponding to the current text field input about the curve period. /// /// The double value corresponding to the curent text field input /// for the curve period parameter. public static double GetPeriod() { return periodVal; } /// /// Gets the value corresponding to the current text field input about the curve /// number of cycles. /// /// The double value corresponding to the curent text field input /// for the curve number of cycles parameter. public static double GetNumberOfCycles() { return cyclesVal; } /// /// Gets the value corresponding to the current text field about the curve amplitude. /// /// The double value corresponding to the curent text field input /// for the curve amplitude parameter. public static double GetAplitude() { return amplitudeVal; } /// /// Gets the value corresponding to the current text field about the number of partitions. /// /// The double value corresponding to the curent text field input for the /// number of partitions. public static double GetNumberOfPartitions() { return partitionsVal; } /// /// Adds a drop down menu for selection of a type of prism. This four types /// correspond to 4 family symbols already loaded in the working Revit document. /// /// the RibbonPanel where the UI element is added private void AddPrismComboBox(RibbonPanel panel) { // create a four members combo box for family instance selection //Family instance #1 ComboBoxMemberData comboBoxMemberData1 = new ComboBoxMemberData("cylinder", "cylinder prism"); //Family instance #2 ComboBoxMemberData comboBoxMemberData2 = new ComboBoxMemberData("rectangle", "rectangular prism"); //Family instance #3 ComboBoxMemberData comboBoxMemberData3 = new ComboBoxMemberData("regularpolygon", "regular polygon prism"); //Family instance #4 ComboBoxMemberData comboBoxMemberData4 = new ComboBoxMemberData("isotriangle", "isotriangle prism"); //make a combo box group group ComboBoxData comboBxData = new ComboBoxData("ComboBox"); prismComboBox = panel.AddItem(comboBxData) as ComboBox; prismComboBox.ToolTip = "select a prism to array on a curve"; prismComboBox.AddItem(comboBoxMemberData1); prismComboBox.AddItem(comboBoxMemberData2); prismComboBox.AddItem(comboBoxMemberData3); prismComboBox.AddItem(comboBoxMemberData4); } /// /// Adds a group of text fields for accepting user input for the various parameters /// of the sine curve (cycles, period, amplitude). /// /// the RibbonPanel where the UI element is added private void AddCurvePropertiesTextFields(RibbonPanel panel) { //Inactive textfields that just display information about the active input fields TextBoxData periodLabelData = new TextBoxData("curve period field"); TextBoxData cyclesLabelData = new TextBoxData("curve cycles field"); TextBoxData amplitudeLabelData = new TextBoxData("curve amplitude field"); //Stack them horizontally IList textFieldList = panel.AddStackedItems(periodLabelData, cyclesLabelData, amplitudeLabelData); //Call method to customize the text boxes and make them inactive String periodToolTip = "A double value denoting the period of the curve, i.e. how often the curve goes a full repition around the unit circle."; CustomizeTextBox(panel, (TextBox)textFieldList[0], periodToolTip, "curve period:", 0, false, 130); String cyclesToolTip = "A double value denoting the number of circles the curve makes."; CustomizeTextBox(panel, (TextBox)textFieldList[1], cyclesToolTip, "curve cycles:", 0, false, 130); String amplitudeToolTip = "A double value denoting how far the curve gets away from the x-axis."; CustomizeTextBox(panel, (TextBox)textFieldList[2], amplitudeToolTip, "curve amplitude:", 0, false, 130); //Active text fields for user input TextBoxData periodBoxData = new TextBoxData("curve period"); TextBoxData cyclesBoxData = new TextBoxData("curve cycles"); TextBoxData amplitudeBoxData = new TextBoxData("curve amplitude"); //Stack them horizontally IList textBoxList = panel.AddStackedItems(periodBoxData, cyclesBoxData, amplitudeBoxData); periodBox = (TextBox)textBoxList[0]; cyclesBox = (TextBox)textBoxList[1]; amplitudeBox = (TextBox)textBoxList[2]; //Call method to customize the text boxes and make them active CustomizeTextBox(panel, periodBox, "Define the period of the sine curve", "" + periodVal, periodVal, true, 50); CustomizeTextBox(panel, cyclesBox, "Define the number of cycles of the sine curve", "" + cyclesVal, cyclesVal, true, 50); CustomizeTextBox(panel, amplitudeBox, "Define the amplitude of the sine curve", "" + amplitudeVal, amplitudeVal, true, 50); } /// /// Add a text field for accepting user input for how many family instances to array on /// the curve. /// /// the RibbonPanel where the UI element is added private void AddPartitionsTextField(RibbonPanel panel) { TextBoxData partitionsFieldData = new TextBoxData("curve partitions field"); TextBox partitionsFieldBox = panel.AddItem(partitionsFieldData) as TextBox; //Call method to customize the text box and set it as inactive CustomizeTextBox(panel, partitionsFieldBox, null, "number of partitions:", 0, false, 130); //Call method to customize the text box and set it as active TextBoxData partitionsBoxData = new TextBoxData("curve partitions box"); partitionsBox = panel.AddItem(partitionsBoxData) as TextBox; CustomizeTextBox(panel, partitionsBox, "Define the number of partitions", "" + partitionsVal, partitionsVal, true, 50); } /// /// Adds button that arrays family instances of curves given the various /// user inputs. /// /// the RibbonPanel where the UI element is added private void AddRunButton(RibbonPanel panel) { PushButtonData pushButtonData = new PushButtonData("arrayPrisms", "run", assemblyPath + "\\" + assemblyName, "Revit.SDK.Samples.SinePlotter.CS.Command"); pushButtonData.LargeImage = new BitmapImage(new Uri(imageFolder + "Start.png")); PushButton pushButton = panel.AddItem(pushButtonData) as PushButton; } private void CustomizeTextBox(RibbonPanel panel, TextBox txtBox, String tip, String displayedText, double defaultVal, Boolean isEnabled, int width) { txtBox.Value = displayedText; txtBox.ToolTip = tip; txtBox.Width = width; txtBox.Enabled = isEnabled; if (isEnabled) { txtBox.EnterPressed += new EventHandler(TextBoxEnterPressed); } } /// /// Handles the action of the text box user input. Checks if the input value is an /// acceptable double value and if it lies among the acceptable range of values; if /// it is it updates the corresponding field variable, if not it displays a warning /// message to the user and retains the previous value. /// /// /// The event arguments used by ComboBox's CurrentChanged event. /// private void TextBoxEnterPressed(object sender, TextBoxEnterPressedEventArgs e) { //cast sender as TextBox to retrieve text value TextBox textBox = sender as TextBox; double value; if (double.TryParse(textBox.Value.ToString(), out value)) { if ((textBox.Name).Equals(periodBox.Name)) { if (value < 0.1 || value > 3) TaskDialog.Show("TextBox Input", "The input value for " + textBox.Name + " has to be between 0.1 and 3.0"); else periodVal = value; } else if ((textBox.Name).Equals(cyclesBox.Name)) { if (value <= 0) TaskDialog.Show("TextBox Input", "The input value for " + textBox.Name + " has to be greater than zero."); else cyclesVal = value; } else if ((textBox.Name).Equals(amplitudeBox.Name)) { if (value < -4 || value > 4) TaskDialog.Show("TextBox Input", "The input value for " + textBox.Name + " has to be between -4.0 and 4.0"); else amplitudeVal = value; } else { if (value <= 0) TaskDialog.Show("TextBox Input", "The input value for " + textBox.Name + " has to be greater than zero."); else partitionsVal = value; } } else { TaskDialog.Show("TextBox Input", "The input value for " + textBox.Name + " has to be a double."); } } /// /// Returns the path of the main project directory. /// /// A string object corresponding to the full path of the main project directory. private String GetProjectDirectory() { //get the absolut path of the assembly string assemblyPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); //move two directory levels back String grandParentDir = Directory.GetParent(assemblyPath).Parent.FullName; return grandParentDir; } #endregion } }