package holeg.ui.view.inspector; import holeg.interfaces.LocalMode; import holeg.interfaces.TimelineDependent; import holeg.model.HolonElement; import holeg.model.HolonSwitch; import holeg.preferences.ColorPreference; import holeg.preferences.ImagePreference; import holeg.ui.controller.Control; import holeg.ui.model.GuiSettings; import holeg.ui.view.image.Import; import holeg.utility.listener.ResizeListener; import holeg.utility.math.Maths; import holeg.utility.math.decimal.Format; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.event.ItemEvent; import java.util.Set; import java.util.logging.Logger; import java.util.stream.Collectors; import javax.swing.Box; import javax.swing.GrayFilter; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JToolBar; public class Inspector extends JSplitPane { private static final Logger log = Logger.getLogger(Inspector.class.getName()); private final UnitGraph unitGraph; private final InspectorTable table; private final JPanel scrollGraph = new JPanel(); private final JPanel graphLabel = new JPanel(); private final JLabel maxGraph = new JLabel("100%"); private final JLabel medGraph = new JLabel("50%"); private final JLabel minGraph = new JLabel("0%"); private final JPanel globalCurveLabel = new JPanel(); private final JLabel minEnergy = new JLabel("0.0"); private final JLabel maxEnergy = new JLabel("0.0"); private final JLabel zeroEnergy = new JLabel("0.0"); private final JToolBar toolBarGraph = new JToolBar(); private final ImageIcon localPeriodButtonImageEnabled = new ImageIcon( Import.loadImage(ImagePreference.Button.Inspector.Graph)); private final ImageIcon localPeriodButtonImageDisabled = new ImageIcon( GrayFilter.createDisabledImage(Import.loadImage(ImagePreference.Button.Inspector.Graph))); private String[] comboContext = {"", "5", "10", "20", "100", "1000"}; private JComboBox localPeriodInput = new JComboBox(comboContext); private JButton resetButton = new JButton("", new ImageIcon(Import.loadImage(ImagePreference.Button.Inspector.Reset))); private JButton localPeriodButton = new JButton("", localPeriodButtonImageEnabled); public Inspector(Control control) { table = new InspectorTable(control); unitGraph = new UnitGraph(control); table.OnElementSelectionChanged.addListener(this::updateUnitGraph); initUI(); control.OnSelectionChanged.addListener(this::updateGlobalCurve); } private void initUI() { this.setOrientation(JSplitPane.VERTICAL_SPLIT); JScrollPane scrollPane = new JScrollPane(table); scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); this.setTopComponent(scrollPane); this.setBottomComponent(scrollGraph); this.setDividerLocation(550); scrollGraph.setLayout(new BorderLayout()); scrollGraph.add(unitGraph, BorderLayout.CENTER); // Set up of the Properties section graphLabel.setLayout(new BorderLayout(0, 10)); graphLabel.add(maxGraph, BorderLayout.NORTH); graphLabel.add(medGraph, BorderLayout.CENTER); graphLabel.add(minGraph, BorderLayout.SOUTH); globalCurveLabel.setLayout(null); globalCurveLabel.setMinimumSize(new Dimension(20, 0)); globalCurveLabel.setPreferredSize(new Dimension(20, 0)); maxEnergy.setForeground(Color.red); minEnergy.setForeground(Color.red); zeroEnergy.setForeground(ColorPreference.UnitGraph.ZeroLineColor); globalCurveLabel.add(maxEnergy); globalCurveLabel.add(zeroEnergy); globalCurveLabel.add(minEnergy); this.globalCurveLabel.addComponentListener((ResizeListener) resize -> updateGlobalCurve()); toolBarGraph.setFloatable(false); toolBarGraph.setAlignmentY(Component.RIGHT_ALIGNMENT); localPeriodButton.setToolTipText("Toggle Local/Global Mode"); toolBarGraph.add(localPeriodButton); // ComboBox localPeriodInput.setEditable(true); localPeriodInput.setVisible(false); localPeriodInput.setMaximumSize(new Dimension(20, 23)); localPeriodInput.addItemListener(aListener -> { if (aListener.getStateChange() == ItemEvent.DESELECTED) { validateInput(localPeriodInput.getEditor().getItem().toString(), true); } }); toolBarGraph.add(localPeriodInput); // localPeriodButtonFunction localPeriodButton.addActionListener(actionEvent -> { boolean newState = !localPeriodInput.isVisible(); changeLocalPeriodButtonAppearance(newState); log.info("LocalPeriodButton"); }); toolBarGraph.add(Box.createHorizontalGlue()); resetButton.setToolTipText("Reset"); resetButton.addActionListener(actionEvent -> unitGraph.reset()); toolBarGraph.add(resetButton); scrollGraph.add(graphLabel, BorderLayout.WEST); scrollGraph.add(globalCurveLabel, BorderLayout.EAST); scrollGraph.add(toolBarGraph, BorderLayout.NORTH); } /** * Validate the LocalMode Input and when its valid save on the Element. * * @param text the inputText to validate. * @param bShowMessage when true, open a MessageDialog when text invalid. */ private void validateInput(String text, boolean bShowMessage) { int localPeriodInputValue; try { localPeriodInputValue = Integer.parseInt(text); } catch (NumberFormatException e) { if (bShowMessage) { JOptionPane.showMessageDialog(null, '"' + text + '"' + " is not a valid Input. \n Use whole numbers."); } return; } LocalMode.Period period = new LocalMode.Period(7); period.setInterval(localPeriodInputValue); unitGraph.setPeriod(period); } /** * This Method updates the UnitGraph, saves the old LocalModeState and load the new * LocalModeState. * * @param elements The new Element to load the UnitGraph */ private void updateUnitGraph(Set elements) { // SaveOld LocalMode State. if (localPeriodInput.isVisible()) { // Save Old State validateInput(localPeriodInput.getEditor().getItem().toString(), false); } // Update UnitGraph unitGraph.clearSeries(); for (TimelineDependent element : elements) { unitGraph.addNewSeries(element); } if (elements.isEmpty()) { GuiSettings.getSelectedObjects().stream().filter(obj -> obj instanceof HolonSwitch) .forEach(obj -> unitGraph.addNewSeries((HolonSwitch) obj)); } // if (elements.isEmpty()) { // this.setDividerLocation(1.0); // } // Load LocalMode State. changeLocalPeriodButtonAppearance(unitGraph.isUsingLocalPeriod()); localPeriodInput.getEditor() .setItem( unitGraph.isLocalPeriedDifferentInSeries() ? "-" : unitGraph.getFirstLocalPeriod()); } private void updateGlobalCurve() { Set elements = InspectorTable.extractElements(GuiSettings.getSelectedObjects()) .collect(Collectors.toSet()); unitGraph.setGlobalCurve(elements); double maxEnergy = elements.stream().map(HolonElement::getEnergy).filter(energy -> energy > 0) .reduce(0.0f, Float::sum); double minEnergy = elements.stream().map(HolonElement::getEnergy).filter(energy -> energy < 0) .reduce(0.0f, Float::sum); double percentage = Maths.invLerp(maxEnergy, minEnergy, 0.0); int widgetHeight = this.globalCurveLabel.getHeight(); int textMiddle = this.zeroEnergy.getPreferredSize().height / 4; int zeroYPos = (int) (widgetHeight * percentage) - 5; this.minEnergy.setText(Format.doubleTwoPlaces(minEnergy)); this.maxEnergy.setText(Format.doubleTwoPlaces(maxEnergy)); this.maxEnergy.setBounds(0, 0, this.maxEnergy.getPreferredSize().width, this.maxEnergy.getPreferredSize().height); this.minEnergy.setBounds(0, widgetHeight - this.minEnergy.getPreferredSize().height, this.minEnergy.getPreferredSize().width, this.minEnergy.getPreferredSize().height); this.zeroEnergy.setBounds(0, zeroYPos, this.zeroEnergy.getPreferredSize().width, this.zeroEnergy.getPreferredSize().height); this.globalCurveLabel.setPreferredSize(new Dimension( Math.max(this.zeroEnergy.getPreferredSize().width, Math.max(this.maxEnergy.getPreferredSize().width, this.minEnergy.getPreferredSize().width)), 0)); } /** * Displayed the actual LocalModeState. * * @param enabled */ private void changeLocalPeriodButtonAppearance(boolean enabled) { localPeriodInput.setVisible(enabled); localPeriodButton.setIcon( enabled ? localPeriodButtonImageEnabled : localPeriodButtonImageDisabled); } }