package org.geogebra.desktop.gui.dialog; import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.GridLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Dictionary; import java.util.Enumeration; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JSlider; import javax.swing.JToggleButton; import javax.swing.border.TitledBorder; import javax.swing.colorchooser.AbstractColorChooserPanel; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.geogebra.common.awt.GColor; import org.geogebra.common.gui.SetLabels; import org.geogebra.common.gui.UpdateFonts; import org.geogebra.common.gui.dialog.options.model.ColorObjectModel; import org.geogebra.common.gui.dialog.options.model.ColorObjectModel.IColorObjectListener; import org.geogebra.common.kernel.algos.AlgoBarChart; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.main.App; import org.geogebra.common.main.Localization; import org.geogebra.desktop.awt.GColorD; import org.geogebra.desktop.gui.color.GeoGebraColorChooser; import org.geogebra.desktop.gui.properties.UpdateablePropertiesPanel; import org.geogebra.desktop.util.GuiResourcesD; /** * panel color chooser and preview panel */ class ColorPanel extends JPanel implements ActionListener, UpdateablePropertiesPanel, ChangeListener, SetLabels, UpdateFonts, IColorObjectListener { /** * */ private final PropertiesPanelD propertiesPanelD; private static final long serialVersionUID = 1L; private ColorObjectModel model; private JLabel previewLabel, currentColorLabel; private PreviewPanel previewPanel; private JPanel opacityPanel, colorChooserContainer; private JRadioButton rbtnForegroundColor, rbtnBackgroundColor; private JButton btnClearBackground; private JSlider opacitySlider; private JPanel previewMetaPanel; private Color selectedColor; private JPanel southPanel; private JCheckBox automatic; // For handle single bar private JToggleButton[] selectionBarButtons; private int selectedBarButton; private JPanel barsPanel; private boolean isBarChart = false; public ColorPanel(PropertiesPanelD propertiesPanelD, GeoGebraColorChooser colChooser) { this.propertiesPanelD = propertiesPanelD; model = new ColorObjectModel(this.propertiesPanelD.app); model.setListener(this); previewPanel = new PreviewPanel(); previewLabel = new JLabel(); currentColorLabel = new JLabel(); automatic = new JCheckBox(); automatic.addActionListener(this); // prepare color chooser colChooser.setLocale(this.propertiesPanelD.app.getLocale()); colChooser.getSelectionModel().addChangeListener(this); // get the color chooser panel AbstractColorChooserPanel colorChooserPanel = colChooser .getChooserPanels()[0]; // create opacity slider opacitySlider = new JSlider(0, 100); opacitySlider.setMajorTickSpacing(25); opacitySlider.setMinorTickSpacing(5); opacitySlider.setPaintTicks(true); opacitySlider.setPaintLabels(true); opacitySlider.setSnapToTicks(true); updateSliderFonts(); rbtnForegroundColor = new JRadioButton(); rbtnBackgroundColor = new JRadioButton(); ButtonGroup group = new ButtonGroup(); group.add(rbtnForegroundColor); group.add(rbtnBackgroundColor); rbtnForegroundColor.setSelected(true); rbtnBackgroundColor.addActionListener(this); rbtnForegroundColor.addActionListener(this); btnClearBackground = new JButton(this.propertiesPanelD.app .getImageIcon(GuiResourcesD.DELETE_SMALL)); btnClearBackground.setFocusPainted(false); btnClearBackground.addActionListener(this); // panel to hold color chooser colorChooserContainer = new JPanel(new FlowLayout(FlowLayout.LEFT)); colorChooserContainer.add(colorChooserPanel); // panel to hold opacity slider opacityPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); opacityPanel.add(opacitySlider); // panel to hold preview previewMetaPanel = new JPanel(new FlowLayout()); previewMetaPanel.add(previewLabel); previewMetaPanel.add(previewPanel); previewMetaPanel.add(currentColorLabel); // vertical box panel that stacks the preview and opacity slider // together southPanel = new JPanel(); southPanel.setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); c.anchor = GridBagConstraints.WEST; c.gridx = 0; southPanel.add(previewMetaPanel, c); southPanel.add(opacityPanel, c); c.gridwidth = 2; southPanel.add(rbtnForegroundColor, c); c.gridwidth = 1; southPanel.add(rbtnBackgroundColor, c); c.gridwidth = GridBagConstraints.REMAINDER; c.insets = new Insets(0, 30, 0, 0); southPanel.add(btnClearBackground, c); // put the sub-panels together setLayout(new BorderLayout()); southPanel.add(automatic); add(colorChooserContainer, BorderLayout.NORTH); add(southPanel, this.propertiesPanelD.loc.borderWest()); } /** * Extended JPanel that draws a preview rectangle filled with the color of * the currently selected GeoElement(s). If the geo is fillable the panel * paints a transparent rectangle using the geo's alpha value. An opaque 2 * pixel border is drawn around the transparent interior. * */ protected class PreviewPanel extends JPanel { private static final long serialVersionUID = 1L; private Color alphaFillColor; public PreviewPanel() { setPreferredSize(new Dimension(80, ColorPanel.this.propertiesPanelD.app.getGUIFontSize() + 16)); setMaximumSize(this.getPreferredSize()); this.setBorder(BorderFactory.createEmptyBorder()); this.setBackground(null); this.setOpaque(true); } /** * Sets the preview colors. * * @param color * @param alpha */ public void setPreview(Color color, double alpha) { if (color == null) { alphaFillColor = getBackground(); setForeground(getBackground()); } else { float[] rgb = new float[3]; color.getRGBColorComponents(rgb); alphaFillColor = new Color(rgb[0], rgb[1], rgb[2], (float) alpha); setForeground(new Color(rgb[0], rgb[1], rgb[2], 1f)); } this.repaint(); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; Insets insets = getInsets(); int w = this.getWidth() - insets.left - insets.right; int h = this.getHeight() - insets.top - insets.bottom; g2.setPaint(Color.WHITE); g.fillRect(insets.left, insets.top, w, h); g2.setPaint(alphaFillColor); g.fillRect(insets.left, insets.top, w, h); g2.setPaint(getForeground()); g2.setStroke(new BasicStroke(3)); g.drawRect(insets.left + 3, insets.top + 3, w - 7, h - 7); g2.setPaint(Color.LIGHT_GRAY); g2.setStroke(new BasicStroke(1)); g.drawRect(insets.left, insets.top, w - 1, h - 1); g2.setPaint(Color.WHITE); g2.setStroke(new BasicStroke(1)); g2.drawRect(insets.left + 1, insets.top + 1, w - 3, h - 3); } } @Override public void setLabels() { Localization loc = this.propertiesPanelD.app.getLocalization(); previewLabel .setText(loc.getMenu("Preview") + ": "); opacityPanel.setBorder(BorderFactory.createTitledBorder( loc.getMenu("Opacity"))); this.propertiesPanelD.colChooser .setLocale(this.propertiesPanelD.app.getLocale()); rbtnBackgroundColor.setText(loc.getMenu("BackgroundColor")); rbtnForegroundColor.setText(loc.getMenu("ForegroundColor")); btnClearBackground.setToolTipText(loc.getMenu("Remove")); this.automatic.setText(loc.getMenu("Automatic")); updateToolTipText(); } @Override public JPanel updatePanel(Object[] geos) { model.setGeos(geos); addSelectionBar(); return update(); } public JPanel update() { if (!model.checkGeos()) { return null; } model.updateProperties(); rbtnBackgroundColor.setVisible(model.hasBackground()); rbtnForegroundColor.setVisible(model.hasBackground()); btnClearBackground.setVisible( rbtnBackgroundColor.isSelected() && model.hasBackground()); btnClearBackground.setEnabled(rbtnBackgroundColor.isSelected()); // hide the color chooser and preview if we have an image colorChooserContainer .setVisible(!model.hasImageGeo() && !model.isSequentialColor()); previewMetaPanel.setVisible(!model.hasImageGeo()); automatic.setVisible(model.hasDefaultGeos()); automatic.setSelected(model.isSequentialColor()); return this; } // Methods that set value for single bar if single bar is selected // and bar has tag for value private void setPreview(GeoElement geo, double alpha0) { AlgoBarChart algo = (AlgoBarChart) geo.getParentAlgorithm(); double alpha = alpha0; if (selectedBarButton != 0 && (algo.getBarAlpha(selectedBarButton) != -1)) { alpha = algo.getBarAlpha(selectedBarButton); } previewPanel.setPreview(selectedColor, alpha); } private void setOpacitySlider(GeoElement geo, double alpha) { /* * AlgoBarChart algo=(AlgoBarChart) geo.getParentAlgorithm(); if * (selectedBarButton != 0 && algo.getBarAlpha(selectedBarButton) != -1) * { alpha = algo.getBarAlpha(selectedBarButton); } * opacitySlider.setValue(Math.round(alpha * 100)); */ } private void setChooser(GeoElement geo0) { if (geo0.getParentAlgorithm() instanceof AlgoBarChart) { AlgoBarChart algo = (AlgoBarChart) geo0.getParentAlgorithm(); if (selectedBarButton != 0 && algo.getBarColor(selectedBarButton) != null) { GColor color = algo.getBarColor(selectedBarButton); selectedColor = new Color(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); } } this.propertiesPanelD.colChooser.getSelectionModel() .setSelectedColor(selectedColor); } private void updateToolTipText() { // set the preview tool tip and color label text for the chosen // color if (selectedColor == null) { previewPanel.setToolTipText(""); } else { previewPanel.setToolTipText( getToolTipText(propertiesPanelD.app, selectedColor)); } currentColorLabel.setText(previewPanel.getToolTipText()); } /** * Sets the tooltip string for a given color * * @param app * application * * @param color * color * @return tooltip */ public String getToolTipText(App app, Color color) { return ColorObjectModel.getColorAsString(app, GColorD.newColor(color)); } // Add tag for color and alpha or remove if selected all bars private void updateBarsColorAndAlpha(GeoElement geo, Color col, double alpha, boolean updateAlphaOnly) { AlgoBarChart algo = (AlgoBarChart) geo.getParentAlgorithm(); if (selectedBarButton == 0) { for (int i = 1; i < selectionBarButtons.length; i++) { algo.setBarColor(null, i); algo.setBarAlpha(-1, i); } geo.setAlphaValue(alpha); if (!updateAlphaOnly) { geo.setObjColor(GColorD.newColor(col)); } algo.setBarAlpha(alpha, selectedBarButton); return; } if (!updateAlphaOnly) { algo.setBarColor(GColorD.newColor(col), selectedBarButton); } algo.setBarAlpha(alpha, selectedBarButton); // For barchart opacity color and // opacity image have same value if there is a tag this.propertiesPanelD.fillingPanel.opacitySlider .removeChangeListener(this.propertiesPanelD.fillingPanel); this.propertiesPanelD.fillingPanel.opacitySlider .setValue((int) Math.round(alpha * 100)); this.propertiesPanelD.fillingPanel.opacitySlider .addChangeListener(this.propertiesPanelD.fillingPanel); } // Add panel for single bar if is a BarChart private void addSelectionBar() { if (barsPanel != null) { remove(barsPanel); } // AlgoElement algo = model.getGeoAt(0).getParentAlgorithm(); if (model.isBarChart()) { int numBar = model.getBarChartIntervals(); isBarChart = true; selectionBarButtons = new JToggleButton[numBar + 1]; ButtonGroup group = new ButtonGroup(); barsPanel = new JPanel(new GridLayout(0, 3, 5, 5)); barsPanel.setBorder(new TitledBorder( this.propertiesPanelD.loc.getPlain("SelectedBar"))); for (int i = 0; i < numBar + 1; i++) { selectionBarButtons[i] = new JToggleButton( this.propertiesPanelD.loc.getPlain("BarA", i + "")); selectionBarButtons[i].setSelected(false); selectionBarButtons[i].setActionCommand("" + i); selectionBarButtons[i].addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { selectedBarButton = Integer .parseInt(((JToggleButton) arg0.getSource()) .getActionCommand()); ColorPanel.this.update(); } }); barsPanel.add(selectionBarButtons[i]); group.add(selectionBarButtons[i]); } selectionBarButtons[0] .setText(this.propertiesPanelD.loc.getPlain("AllBars")); selectionBarButtons[selectedBarButton].setSelected(true); add(barsPanel, this.propertiesPanelD.loc.borderEast()); } } /** * Listens for color chooser state changes */ @Override public void stateChanged(ChangeEvent e) { float alpha = opacitySlider.getValue() / 100.0f; GColor color = GColorD .newColor(this.propertiesPanelD.colChooser.getColor()); if (e.getSource() == opacitySlider) { model.applyChanges(color, alpha, true); } else { model.applyChanges(color, alpha, false); } } /** * action listener implementation for label mode combobox */ @Override public void actionPerformed(ActionEvent e) { Object source = e.getSource(); if (source == rbtnBackgroundColor || source == rbtnForegroundColor) { addSelectionBar(); update(); } if (source == btnClearBackground) { model.clearBackgroundColor(); addSelectionBar(); update(); } if (source == automatic) { model.setSequential(automatic.isSelected()); update(); } } @Override public void updateFonts() { Font font = this.propertiesPanelD.app.getPlainFont(); previewLabel.setFont(font); currentColorLabel.setFont(font); opacityPanel.setFont(font); // colChooser.setFont(font); rbtnBackgroundColor.setFont(font); rbtnForegroundColor.setFont(font); btnClearBackground.setFont(font); updateSliderFonts(); } private void updateSliderFonts() { // set slider label font Dictionary<?, ?> labelTable = opacitySlider.getLabelTable(); Enumeration<?> en = labelTable.elements(); JLabel label; while (en.hasMoreElements()) { label = (JLabel) en.nextElement(); label.setFont(this.propertiesPanelD.app.getSmallFont()); } } @Override public void updateVisualStyle(GeoElement geo) { if (model.getGeos() == null) { return; } update(); } @Override public void updateChooser(boolean equalObjColor, boolean equalObjColorBackground, boolean allFillable, boolean hasBackground, boolean hasOpacity) { // initialize selected color and opacity selectedColor = null; Color selectedBGColor = null; double alpha = 1; GeoElement geo0 = model.getGeoAt(0); if (equalObjColorBackground) { selectedBGColor = GColorD.getAwtColor(geo0.getBackgroundColor()); } if (isBackgroundColorSelected()) { selectedColor = selectedBGColor; } else { // set selectedColor if all selected geos have the same color if (equalObjColor) { if (allFillable) { selectedColor = GColorD.getAwtColor(geo0.getFillColor()); alpha = geo0.getAlphaValue(); // can be -1 for lists if (alpha < 0) { alpha = 0; } } else { selectedColor = GColorD.getAwtColor(geo0.getObjectColor()); } } } updateToolTipText(); // set the chooser color this.propertiesPanelD.colChooser.getSelectionModel() .removeChangeListener(this); if (isBarChart) { setChooser(geo0); } else { this.propertiesPanelD.colChooser.getSelectionModel() .setSelectedColor(selectedColor); } this.propertiesPanelD.colChooser.getSelectionModel() .addChangeListener(this); // set the opacity opacitySlider.removeChangeListener(this); if (allFillable && hasOpacity) { // show opacity slider and set to // first geo's // alpha value opacityPanel.setVisible(true); alpha = geo0.getAlphaValue(); // can be -1 for lists if (alpha < 0) { alpha = 0; } if (isBarChart) { setOpacitySlider(geo0, alpha); } else { opacitySlider.setValue((int) Math.round(alpha * 100)); } } else { // hide opacity slider and set alpha = 1 opacityPanel.setVisible(false); alpha = 1; opacitySlider.setValue((int) Math.round(alpha * 100)); } opacitySlider.addChangeListener(this); // set the preview panel (do this after the alpha level is set // above) if (geo0.getParentAlgorithm() instanceof AlgoBarChart) { isBarChart = true; setPreview(geo0, alpha); } else { isBarChart = false; previewPanel.setPreview(selectedColor, alpha); } } @Override public void updatePreview(GColor col, double alpha) { // update preview panel Color color = GColorD.getAwtColor(col); previewPanel.setPreview(color, alpha); previewPanel .setToolTipText(getToolTipText(propertiesPanelD.app, color)); currentColorLabel.setText(previewPanel.getToolTipText()); } @Override public boolean isBackgroundColorSelected() { return rbtnBackgroundColor.isSelected(); } @Override public void updateNoBackground(GeoElement geo, GColor col, double alpha, boolean updateAlphaOnly, boolean allFillable) { Color color = GColorD.getAwtColor(col); if (!updateAlphaOnly) { if (isBarChart) { updateBarsColorAndAlpha(geo, color, alpha, updateAlphaOnly); } else { geo.setObjColor(col); } } if (allFillable) { if (isBarChart) { updateBarsColorAndAlpha(geo, color, alpha, updateAlphaOnly); } else { geo.setAlphaValue(alpha); } } automatic.setSelected(geo.isAutoColor()); } } // ColorPanel