diff options
author | erikj <none@none> | 2017-09-12 19:03:39 +0200 |
---|---|---|
committer | erikj <none@none> | 2017-09-12 19:03:39 +0200 |
commit | 5ed9fb4367908cf380f1191a55f479ae335d1c87 (patch) | |
tree | bae73db0cb8f29c3370d16b487a0b2fbe3c48ada /src/java.desktop/unix/classes/sun/awt/X11/XCheckboxPeer.java | |
parent | 70cebea6a7eb12b61ca3c162963541168e3339c9 (diff) | |
download | JetBrainsRuntime-5ed9fb4367908cf380f1191a55f479ae335d1c87.tar.gz |
8187443: Forest Consolidation: Move files to unified layout
Reviewed-by: darcy, ihse
Diffstat (limited to 'src/java.desktop/unix/classes/sun/awt/X11/XCheckboxPeer.java')
-rw-r--r-- | src/java.desktop/unix/classes/sun/awt/X11/XCheckboxPeer.java | 477 |
1 files changed, 477 insertions, 0 deletions
diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XCheckboxPeer.java b/src/java.desktop/unix/classes/sun/awt/X11/XCheckboxPeer.java new file mode 100644 index 00000000000..0f4b39fc9bc --- /dev/null +++ b/src/java.desktop/unix/classes/sun/awt/X11/XCheckboxPeer.java @@ -0,0 +1,477 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.awt.X11; + +import java.awt.*; +import java.awt.peer.*; +import java.awt.event.*; +import java.awt.image.BufferedImage; +import javax.swing.plaf.basic.BasicGraphicsUtils; +import java.awt.geom.AffineTransform; +import java.util.Objects; + +import sun.util.logging.PlatformLogger; + +class XCheckboxPeer extends XComponentPeer implements CheckboxPeer { + + private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XCheckboxPeer"); + + private static final Insets focusInsets = new Insets(0,0,0,0); + private static final Insets borderInsets = new Insets(2,2,2,2); + private static final int checkBoxInsetFromText = 2; + + //The check mark is less common than a plain "depressed" button, + //so don't use the checkmark. + // The checkmark shape: + private static final double MASTER_SIZE = 128.0; + private static final Polygon MASTER_CHECKMARK = new Polygon( + new int[] {1, 25,56,124,124,85, 64}, // X-coords + new int[] {59,35,67, 0, 12,66,123}, // Y-coords + 7); + + private Shape myCheckMark; + + private Color focusColor = SystemColor.windowText; + + private boolean pressed; + private boolean armed; + private boolean selected; + + private Rectangle textRect; + private Rectangle focusRect; + private int checkBoxSize; + private int cbX; + private int cbY; + + String label; + CheckboxGroup checkBoxGroup; + + XCheckboxPeer(Checkbox target) { + super(target); + pressed = false; + armed = false; + selected = target.getState(); + label = target.getLabel(); + if ( label == null ) { + label = ""; + } + checkBoxGroup = target.getCheckboxGroup(); + updateMotifColors(getPeerBackground()); + } + + public void preInit(XCreateWindowParams params) { + // Put this here so it is executed before layout() is called from + // setFont() in XComponent.postInit() + textRect = new Rectangle(); + focusRect = new Rectangle(); + super.preInit(params); + } + + public boolean isFocusable() { return true; } + + public void focusGained(FocusEvent e) { + // TODO: only need to paint the focus bit + super.focusGained(e); + repaint(); + } + + public void focusLost(FocusEvent e) { + // TODO: only need to paint the focus bit? + super.focusLost(e); + repaint(); + } + + + void handleJavaKeyEvent(KeyEvent e) { + int i = e.getID(); + switch (i) { + case KeyEvent.KEY_PRESSED: + keyPressed(e); + break; + case KeyEvent.KEY_RELEASED: + keyReleased(e); + break; + case KeyEvent.KEY_TYPED: + keyTyped(e); + break; + } + } + + public void keyTyped(KeyEvent e) {} + + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_SPACE) + { + //pressed=true; + //armed=true; + //selected=!selected; + action(!selected); + //repaint(); // Gets the repaint from action() + } + + } + + public void keyReleased(KeyEvent e) {} + + @Override + public void setLabel(String label) { + if (label == null) { + label = ""; + } + if (!label.equals(this.label)) { + this.label = label; + layout(); + repaint(); + } + } + + void handleJavaMouseEvent(MouseEvent e) { + super.handleJavaMouseEvent(e); + int i = e.getID(); + switch (i) { + case MouseEvent.MOUSE_PRESSED: + mousePressed(e); + break; + case MouseEvent.MOUSE_RELEASED: + mouseReleased(e); + break; + case MouseEvent.MOUSE_ENTERED: + mouseEntered(e); + break; + case MouseEvent.MOUSE_EXITED: + mouseExited(e); + break; + case MouseEvent.MOUSE_CLICKED: + mouseClicked(e); + break; + } + } + + public void mousePressed(MouseEvent e) { + if (XToolkit.isLeftMouseButton(e)) { + Checkbox cb = (Checkbox) e.getSource(); + + if (cb.contains(e.getX(), e.getY())) { + if (log.isLoggable(PlatformLogger.Level.FINER)) { + log.finer("mousePressed() on " + target.getName() + " : armed = " + armed + ", pressed = " + pressed + + ", selected = " + selected + ", enabled = " + isEnabled()); + } + if (!isEnabled()) { + // Disabled buttons ignore all input... + return; + } + if (!armed) { + armed = true; + } + pressed = true; + repaint(); + } + } + } + + public void mouseReleased(MouseEvent e) { + if (log.isLoggable(PlatformLogger.Level.FINER)) { + log.finer("mouseReleased() on " + target.getName() + ": armed = " + armed + ", pressed = " + pressed + + ", selected = " + selected + ", enabled = " + isEnabled()); + } + boolean sendEvent = false; + if (XToolkit.isLeftMouseButton(e)) { + // TODO: Multiclick Threshold? - see BasicButtonListener.java + if (armed) { + //selected = !selected; + // send action event + //action(e.getWhen(),e.getModifiers()); + sendEvent = true; + } + pressed = false; + armed = false; + if (sendEvent) { + action(!selected); // Also gets repaint in action() + } + else { + repaint(); + } + } + } + + public void mouseEntered(MouseEvent e) { + if (log.isLoggable(PlatformLogger.Level.FINER)) { + log.finer("mouseEntered() on " + target.getName() + ": armed = " + armed + ", pressed = " + pressed + + ", selected = " + selected + ", enabled = " + isEnabled()); + } + if (pressed) { + armed = true; + repaint(); + } + } + + public void mouseExited(MouseEvent e) { + if (log.isLoggable(PlatformLogger.Level.FINER)) { + log.finer("mouseExited() on " + target.getName() + ": armed = " + armed + ", pressed = " + pressed + + ", selected = " + selected + ", enabled = " + isEnabled()); + } + if (armed) { + armed = false; + repaint(); + } + } + + public void mouseClicked(MouseEvent e) {} + + public Dimension getMinimumSize() { + /* + * Spacing (number of pixels between check mark and label text) is + * currently set to 0, but in case it ever changes we have to add + * it. 8 is a heuristic number. Indicator size depends on font + * height, so we don't need to include it in checkbox's height + * calculation. + */ + FontMetrics fm = getFontMetrics(getPeerFont()); + + int wdth = fm.stringWidth(label) + getCheckboxSize(fm) + (2 * checkBoxInsetFromText) + 8; + int hght = Math.max(fm.getHeight() + 8, 15); + + return new Dimension(wdth, hght); + } + + private int getCheckboxSize(FontMetrics fm) { + // the motif way of sizing is a bit inscutible, but this + // is a fair approximation + return (fm.getHeight() * 76 / 100) - 1; + } + + public void setBackground(Color c) { + updateMotifColors(c); + super.setBackground(c); + } + + /* + * Layout the checkbox/radio button and text label + */ + public void layout() { + Dimension size = getPeerSize(); + Font f = getPeerFont(); + FontMetrics fm = getFontMetrics(f); + String text = label; + + checkBoxSize = getCheckboxSize(fm); + + // Note - Motif appears to use an left inset that is slightly + // scaled to the checkbox/font size. + cbX = borderInsets.left + checkBoxInsetFromText; + cbY = size.height / 2 - checkBoxSize / 2; + int minTextX = borderInsets.left + 2 * checkBoxInsetFromText + checkBoxSize; + // FIXME: will need to account for alignment? + // FIXME: call layout() on alignment changes + //textRect.width = fm.stringWidth(text); + textRect.width = fm.stringWidth(text == null ? "" : text); + textRect.height = fm.getHeight(); + + textRect.x = Math.max(minTextX, size.width / 2 - textRect.width / 2); + textRect.y = (size.height - textRect.height) / 2; + + focusRect.x = focusInsets.left; + focusRect.y = focusInsets.top; + focusRect.width = size.width-(focusInsets.left+focusInsets.right)-1; + focusRect.height = size.height-(focusInsets.top+focusInsets.bottom)-1; + + double fsize = (double) checkBoxSize; + myCheckMark = AffineTransform.getScaleInstance(fsize / MASTER_SIZE, fsize / MASTER_SIZE).createTransformedShape(MASTER_CHECKMARK); + } + @Override + void paintPeer(final Graphics g) { + //layout(); + Dimension size = getPeerSize(); + Font f = getPeerFont(); + flush(); + g.setColor(getPeerBackground()); // erase the existing button + g.fillRect(0,0, size.width, size.height); + if (label != null) { + g.setFont(f); + paintText(g, textRect, label); + } + + if (hasFocus()) { + paintFocus(g, + focusRect.x, + focusRect.y, + focusRect.width, + focusRect.height); + } + // Paint the checkbox or radio button + if (checkBoxGroup == null) { + paintCheckbox(g, cbX, cbY, checkBoxSize, checkBoxSize); + } + else { + paintRadioButton(g, cbX, cbY, checkBoxSize, checkBoxSize); + } + flush(); + } + + // You'll note this looks suspiciously like paintBorder + public void paintCheckbox(Graphics g, + int x, int y, int w, int h) { + boolean useBufferedImage = false; + BufferedImage buffer = null; + Graphics2D g2 = null; + int rx = x; + int ry = y; + if (!(g instanceof Graphics2D)) { + // Fix for 5045936. While printing, g is an instance of + // sun.print.ProxyPrintGraphics which extends Graphics. So + // we use a separate buffered image and its graphics is + // always Graphics2D instance + buffer = graphicsConfig.createCompatibleImage(w, h); + g2 = buffer.createGraphics(); + useBufferedImage = true; + rx = 0; + ry = 0; + } + else { + g2 = (Graphics2D)g; + } + try { + drawMotif3DRect(g2, rx, ry, w-1, h-1, armed | selected); + + // then paint the check + g2.setColor((armed | selected) ? selectColor : getPeerBackground()); + g2.fillRect(rx+1, ry+1, w-2, h-2); + + if (armed | selected) { + //Paint the check + + // FIXME: is this the right color? + g2.setColor(getPeerForeground()); + + AffineTransform af = g2.getTransform(); + g2.setTransform(AffineTransform.getTranslateInstance(rx,ry)); + g2.fill(myCheckMark); + g2.setTransform(af); + } + } finally { + if (useBufferedImage) { + g2.dispose(); + } + } + if (useBufferedImage) { + g.drawImage(buffer, x, y, null); + } + } + + public void paintRadioButton(Graphics g, int x, int y, int w, int h) { + + g.setColor((armed | selected) ? darkShadow : lightShadow); + g.drawArc(x-1, y-1, w+2, h+2, 45, 180); + + g.setColor((armed | selected) ? lightShadow : darkShadow); + g.drawArc(x-1, y-1, w+2, h+2, 45, -180); + + if (armed | selected) { + g.setColor(selectColor); + g.fillArc(x+1, y+1, w-1, h-1, 0, 360); + } + } + + protected void paintText(Graphics g, Rectangle textRect, String text) { + FontMetrics fm = g.getFontMetrics(); + + int mnemonicIndex = -1; + + if(isEnabled()) { + /*** paint the text normally */ + g.setColor(getPeerForeground()); + BasicGraphicsUtils.drawStringUnderlineCharAt(g,text,mnemonicIndex , textRect.x , textRect.y + fm.getAscent() ); + } + else { + /*** paint the text disabled ***/ + g.setColor(getPeerBackground().brighter()); + + BasicGraphicsUtils.drawStringUnderlineCharAt(g,text, mnemonicIndex, + textRect.x, textRect.y + fm.getAscent()); + g.setColor(getPeerBackground().darker()); + BasicGraphicsUtils.drawStringUnderlineCharAt(g,text, mnemonicIndex, + textRect.x - 1, textRect.y + fm.getAscent() - 1); + } + } + + // TODO: copied directly from XButtonPeer. Should probabaly be shared + protected void paintFocus(Graphics g, int x, int y, int w, int h) { + g.setColor(focusColor); + g.drawRect(x,y,w,h); + } + + @Override + public void setState(boolean state) { + if (selected != state) { + selected = state; + repaint(); + } + } + + @Override + public void setCheckboxGroup(final CheckboxGroup g) { + if (!Objects.equals(g, checkBoxGroup)) { + // If changed from grouped/ungrouped, need to repaint() + checkBoxGroup = g; + repaint(); + } + } + + // NOTE: This method is called by privileged threads. + // DO NOT INVOKE CLIENT CODE ON THIS THREAD! + // From MCheckboxPeer + void action(boolean state) { + final Checkbox cb = (Checkbox)target; + final boolean newState = state; + XToolkit.executeOnEventHandlerThread(cb, new Runnable() { + public void run() { + CheckboxGroup cbg = checkBoxGroup; + // Bugid 4039594. If this is the current Checkbox in + // a CheckboxGroup, then return to prevent deselection. + // Otherwise, it's logical state will be turned off, + // but it will appear on. + if ((cbg != null) && (cbg.getSelectedCheckbox() == cb) && + cb.getState()) { + //inUpCall = false; + cb.setState(true); + return; + } + // All clear - set the new state + cb.setState(newState); + notifyStateChanged(newState); + } + }); + } + + void notifyStateChanged(boolean state) { + Checkbox cb = (Checkbox) target; + ItemEvent e = new ItemEvent(cb, + ItemEvent.ITEM_STATE_CHANGED, + cb.getLabel(), + state ? ItemEvent.SELECTED : ItemEvent.DESELECTED); + postEvent(e); + } +} |