diff --git a/PolymorphicBlocks b/PolymorphicBlocks index 6c87b602..17405f03 160000 --- a/PolymorphicBlocks +++ b/PolymorphicBlocks @@ -1 +1 @@ -Subproject commit 6c87b602a6c88222727c8c745832d28903229e22 +Subproject commit 17405f03d65db06e812b981a9d7cfa34e2f6d6d5 diff --git a/src/main/scala/edg_ide/dse/DseFeature.scala b/src/main/scala/edg_ide/dse/DseFeature.scala index d15d0390..81a21c31 100644 --- a/src/main/scala/edg_ide/dse/DseFeature.scala +++ b/src/main/scala/edg_ide/dse/DseFeature.scala @@ -1,6 +1,5 @@ package edg_ide.dse object DseFeature { - // feature flag to hide the feature while it's still in development - val kEnabled = false + val kEnabled = true } diff --git a/src/main/scala/edg_ide/swing/dse/JDsePlot.scala b/src/main/scala/edg_ide/swing/dse/JDsePlot.scala index 101984b6..261a3a0c 100644 --- a/src/main/scala/edg_ide/swing/dse/JDsePlot.scala +++ b/src/main/scala/edg_ide/swing/dse/JDsePlot.scala @@ -1,6 +1,7 @@ package edg_ide.swing.dse import com.intellij.ui.JBColor +import edg_ide.util.SiPrefixUtil import java.awt.Color import scala.collection.mutable @@ -86,7 +87,7 @@ object JDsePlot { var tickPos = (math.floor(range._1 / tickSpacing) * tickSpacing).toFloat val ticksBuilder = mutable.ArrayBuffer[(Float, String)]() while (tickPos <= range._2) { - ticksBuilder.append((tickPos, f"$tickPos%.02g")) + ticksBuilder.append((tickPos, SiPrefixUtil.unitsToString(tickPos, ""))) tickPos = (tickPos + tickSpacing).toFloat } ticksBuilder.toSeq diff --git a/src/main/scala/edg_ide/ui/DetailPanel.scala b/src/main/scala/edg_ide/ui/DetailPanel.scala index 517dc0e0..37fb2a1f 100644 --- a/src/main/scala/edg_ide/ui/DetailPanel.scala +++ b/src/main/scala/edg_ide/ui/DetailPanel.scala @@ -20,7 +20,7 @@ import edgrpc.hdl.{hdl => edgrpc} import java.awt.datatransfer.StringSelection import java.awt.event.{KeyAdapter, KeyEvent, MouseAdapter, MouseEvent} import java.awt.{BorderLayout, Toolkit} -import javax.swing.{JPanel, JPopupMenu, KeyStroke, SwingUtilities} +import javax.swing.{JMenu, JPanel, JPopupMenu, KeyStroke, SwingUtilities} class DetailParamPopupMenu( path: IndirectDesignPath, @@ -92,9 +92,16 @@ class DetailParamPopupMenu( ) ) + addSeparator() + val hotkeyModifier = Toolkit.getDefaultToolkit.getMenuShortcutKeyMaskEx + val copyValueItem = add(ContextMenuUtils.MenuItemFromErrorable(copyAction, s"Copy value")) + copyValueItem.setMnemonic(KeyEvent.VK_C) + copyValueItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, hotkeyModifier)) + if (DseFeature.kEnabled) { - addSeparator() - add( + val dseMenu = new JMenu("Design Space Exploration") + + dseMenu.add( ContextMenuUtils.MenuItemFromErrorable( exceptable { val directPath = DesignPath.fromIndirectOption(path).exceptNone("not a direct param") @@ -114,7 +121,7 @@ class DetailParamPopupMenu( ) ) - add( + dseMenu.add( ContextMenuUtils.MenuItemNamedFromErrorable( exceptable { val (paramDefiningClass, postfix) = paramDefiningClassPostfix.exceptError @@ -137,8 +144,8 @@ class DetailParamPopupMenu( ) ) - addSeparator() - add( + dseMenu.addSeparator() + dseMenu.add( ContextMenuUtils.MenuItemFromErrorable( exceptable { val objective = compiler.getParamType(path) match { @@ -155,13 +162,10 @@ class DetailParamPopupMenu( "Add objective" ) ) - } - addSeparator() - val hotkeyModifier = Toolkit.getDefaultToolkit.getMenuShortcutKeyMaskEx - val copyValueItem = add(ContextMenuUtils.MenuItemFromErrorable(copyAction, s"Copy value")) - copyValueItem.setMnemonic(KeyEvent.VK_C) - copyValueItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, hotkeyModifier)) + addSeparator() + add(dseMenu) + } } // TODO: remove initCompiler, it's counterintuitive diff --git a/src/main/scala/edg_ide/ui/DsePanel.scala b/src/main/scala/edg_ide/ui/DsePanel.scala index 5443c74d..9e6a36c6 100644 --- a/src/main/scala/edg_ide/ui/DsePanel.scala +++ b/src/main/scala/edg_ide/ui/DsePanel.scala @@ -387,8 +387,10 @@ class DsePanel(project: Project) extends JPanel { val nodePath = new TreePath(treeRoot).pathByAddingChild(treeRoot.searchConfigNode) configTree.getTree.expandPath(nodePath) if (scrollToLast) { - val lastNodePath = nodePath.pathByAddingChild(treeRoot.searchConfigNode.children.last) - configTree.scrollRectToVisible(configTree.getTree.getPathBounds(lastNodePath)) + treeRoot.searchConfigNode.children.lastOption.foreach { last => + val lastNodePath = nodePath.pathByAddingChild(last) + configTree.scrollRectToVisible(configTree.getTree.getPathBounds(lastNodePath)) + } } tabbedPane.setSelectedIndex(kTabConfig) }) @@ -403,8 +405,10 @@ class DsePanel(project: Project) extends JPanel { val nodePath = new TreePath(treeRoot).pathByAddingChild(treeRoot.objectivesNode) configTree.getTree.expandPath(nodePath) if (scrollToLast) { - val lastNodePath = nodePath.pathByAddingChild(treeRoot.objectivesNode.children.last) - configTree.scrollRectToVisible(configTree.getTree.getPathBounds(lastNodePath)) + treeRoot.objectivesNode.children.lastOption.foreach { last => + val lastNodePath = nodePath.pathByAddingChild(last) + configTree.scrollRectToVisible(configTree.getTree.getPathBounds(lastNodePath)) + } } tabbedPane.setSelectedIndex(kTabConfig) }) diff --git a/src/main/scala/edg_ide/ui/tools/DefaultTool.scala b/src/main/scala/edg_ide/ui/tools/DefaultTool.scala index 8f0bc2b5..599d58c5 100644 --- a/src/main/scala/edg_ide/ui/tools/DefaultTool.scala +++ b/src/main/scala/edg_ide/ui/tools/DefaultTool.scala @@ -5,6 +5,7 @@ import com.intellij.openapi.project.Project import com.intellij.util.concurrency.AppExecutorUtil import com.jetbrains.python.psi.search.PyClassInheritorsSearch import edg.EdgirUtils.SimpleLibraryPath +import edg.compiler.FloatValue import edg.util.Errorable import edg.wir.DesignPath import edg.wir.ProtoUtil.ParamProtoToSeqMap @@ -19,7 +20,7 @@ import edgir.schema.schema import java.awt.event.MouseEvent import java.util.concurrent.Callable -import javax.swing.{JLabel, JPopupMenu, SwingUtilities} +import javax.swing.{JLabel, JMenu, JPopupMenu, SwingUtilities} import scala.jdk.CollectionConverters.CollectionHasAsScala trait NavigationPopupMenu extends JPopupMenu { @@ -119,14 +120,14 @@ class DesignBlockPopupMenu(path: DesignPath, interface: ToolInterface) addGotoDefinitionItem(blockClass, project) if (DseFeature.kEnabled) { - addSeparator() + val dseMenu = new JMenu("Design Space Exploration") val rootClass = interface.getDesign.getContents.getSelfClass val refinementClass = block.prerefineClass.getOrElse(block.getSelfClass) - add( + dseMenu.add( ContextMenuUtils.MenuItemFromErrorable( exceptable { - val blockPyClass = DesignAnalysisUtils.pyClassOf(refinementClass, project).get + val blockPyClass = DesignAnalysisUtils.pyClassOf(refinementClass, project).exceptError () => { ReadAction .nonBlocking((() => { @@ -162,7 +163,7 @@ class DesignBlockPopupMenu(path: DesignPath, interface: ToolInterface) f"Search subclasses of ${refinementClass.toSimpleString}" ) ) - add( + dseMenu.add( ContextMenuUtils.MenuItemFromErrorable( exceptable { requireExcept(block.params.toSeqMap.contains("matching_parts"), "block must have matching_parts") @@ -176,7 +177,7 @@ class DesignBlockPopupMenu(path: DesignPath, interface: ToolInterface) ) ) - add( + dseMenu.add( ContextMenuUtils.MenuItem( () => { val config = DseService(project).getOrCreateRunConfiguration(rootClass, this) @@ -186,7 +187,7 @@ class DesignBlockPopupMenu(path: DesignPath, interface: ToolInterface) s"Add objective area" ) ) - add( + dseMenu.add( ContextMenuUtils.MenuItem( () => { val config = DseService(project).getOrCreateRunConfiguration(rootClass, this) @@ -197,7 +198,7 @@ class DesignBlockPopupMenu(path: DesignPath, interface: ToolInterface) ) ) if (path == DesignPath()) { // price only supported at top level for now - add( + dseMenu.add( ContextMenuUtils.MenuItem( () => { val config = DseService(project).getOrCreateRunConfiguration(rootClass, this) @@ -208,16 +209,21 @@ class DesignBlockPopupMenu(path: DesignPath, interface: ToolInterface) ) ) } - add( - ContextMenuUtils.MenuItem( - () => { - val config = DseService(project).getOrCreateRunConfiguration(rootClass, this) - config.options.objectives = config.options.objectives ++ Seq(DseObjectiveUnprovenCount(path)) - DseService(project).onObjectiveConfigChanged(config, true) - }, - "Add unproven count" + if (EdgSettingsState.getInstance().showProvenStatus) { + dseMenu.add( + ContextMenuUtils.MenuItem( + () => { + val config = DseService(project).getOrCreateRunConfiguration(rootClass, this) + config.options.objectives = config.options.objectives ++ Seq(DseObjectiveUnprovenCount(path)) + DseService(project).onObjectiveConfigChanged(config, true) + }, + "Add unproven count" + ) ) - ) + } + + addSeparator() + add(dseMenu) } } @@ -289,6 +295,33 @@ class DesignPortPopupMenu(path: DesignPath, interface: ToolInterface) addGotoDefinitionItem(portClass, project) addGotoConnectItems(path, interface.getDesign, project) + if (DseFeature.kEnabled) { + val dseMenu = new JMenu("Design Space Exploration") + + val params = port match { + case port: elem.Port => port.params + case bundle: elem.Bundle => bundle.params + case _ => Seq() // including arrays, not supported + } + params.toSeqMap.foreach { case (paramName, paramValue) => + dseMenu.add(ContextMenuUtils.MenuItemFromErrorable( + exceptable { + val objective = + DseObjectiveParameter(path.asIndirect + paramName, edg.compiler.ExprValue.classFromValInit(paramValue)) + () => { + val config = + DseService(project).getOrCreateRunConfiguration(interface.getDesign.getContents.getSelfClass, this) + config.options.objectives = config.options.objectives :+ objective + DseService(project).onObjectiveConfigChanged(config, true) + } + }, + f"Add objective $paramName" + )) + } + + addSeparator() + add(dseMenu) + } } class DefaultTool(val interface: ToolInterface) extends BaseTool {