JBR-5551 update hit tests on custom title bar

- set windows always on top
- verify mouse location before clicking

(cherry picked from commit 005de74127)
This commit is contained in:
Sergey Shelomentsev
2023-05-29 17:51:11 +03:00
committed by jbrbot
parent f711c2f3ee
commit 9325fda561
4 changed files with 179 additions and 79 deletions

View File

@@ -22,21 +22,12 @@
*/
import com.jetbrains.JBR;
import util.CommonAPISuite;
import util.Task;
import util.TaskResult;
import util.TestUtils;
import util.*;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.AWTException;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Panel;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
@@ -57,9 +48,18 @@ import java.util.List;
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=3.0 HitTestClientArea
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=3.5 HitTestClientArea
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=4.0 HitTestClientArea
*/
public class HitTestClientArea {
private static final List<Integer> BUTTON_MASKS = List.of(
InputEvent.BUTTON1_DOWN_MASK,
InputEvent.BUTTON2_DOWN_MASK,
InputEvent.BUTTON3_DOWN_MASK
);
private static final int PANEL_WIDTH = 400;
private static final int PANEL_HEIGHT = (int) TestUtils.TITLE_BAR_HEIGHT;
public static void main(String... args) {
TaskResult awtResult = CommonAPISuite.runTestSuite(List.of(TestUtils::createFrameWithCustomTitleBar, TestUtils::createDialogWithCustomTitleBar), hitTestClientAreaAWT);
TaskResult swingResult = CommonAPISuite.runTestSuite(List.of(TestUtils::createJFrameWithCustomTitleBar, TestUtils::createJFrameWithCustomTitleBar), hitTestClientAreaSwing);
@@ -71,22 +71,11 @@ public class HitTestClientArea {
}
}
private static final Task hitTestClientAreaAWT = new Task("Hit test client area AWT") {
private static final List<Integer> BUTTON_MASKS = List.of(
InputEvent.BUTTON1_DOWN_MASK,
InputEvent.BUTTON2_DOWN_MASK,
InputEvent.BUTTON3_DOWN_MASK
);
private static final int PANEL_WIDTH = 400;
private static final int PANEL_HEIGHT = (int) TestUtils.TITLE_BAR_HEIGHT;
private static final Task hitTestClientAreaAWT = new AWTTask("Hit test client area AWT") {
private final int[] gotClicks = new int[BUTTON_MASKS.size()];
private static boolean mousePressed = false;
private static boolean mouseReleased = false;
private Panel panel;
@Override
protected void cleanup() {
Arrays.fill(gotClicks, 0);
@@ -102,7 +91,7 @@ public class HitTestClientArea {
@Override
protected void customizeWindow() {
panel = new Panel(){
Panel panel = new Panel() {
@Override
public void paint(Graphics g) {
Rectangle r = g.getClipBounds();
@@ -140,6 +129,7 @@ public class HitTestClientArea {
});
window.add(panel);
window.setAlwaysOnTop(true);
}
@Override
@@ -151,24 +141,17 @@ public class HitTestClientArea {
window.requestFocus();
for (Integer mask: BUTTON_MASKS) {
robot.waitForIdle();
robot.mouseMove(initialX, initialY);
robot.mousePress(mask);
robot.mouseRelease(mask);
robot.waitForIdle();
MouseUtils.verifyLocationAndClick(robot, window, initialX, initialY, mask);
}
Point initialLocation = window.getLocationOnScreen();
robot.waitForIdle();
robot.mouseMove(initialX, initialY);
MouseUtils.verifyLocationAndMove(robot, window, initialX, initialY);
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
for (int i = 0; i < 10; i++) {
initialX += 3;
initialY += 3;
robot.delay(300);
robot.mouseMove(initialX, initialY);
MouseUtils.verifyLocationAndMove(robot, window, initialX, initialY);
}
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
robot.waitForIdle();
@@ -196,21 +179,12 @@ public class HitTestClientArea {
};
private static final Task hitTestClientAreaSwing = new Task("Hit test client area Swing") {
private static final List<Integer> BUTTON_MASKS = List.of(
InputEvent.BUTTON1_DOWN_MASK,
InputEvent.BUTTON2_DOWN_MASK,
InputEvent.BUTTON3_DOWN_MASK
);
private static final int PANEL_WIDTH = 400;
private static final int PANEL_HEIGHT = (int) TestUtils.TITLE_BAR_HEIGHT;
private static final Task hitTestClientAreaSwing = new SwingTask("Hit test client area Swing") {
private final int[] gotClicks = new int[BUTTON_MASKS.size()];
private static boolean mousePressed = false;
private static boolean mouseReleased = false;
private JPanel panel;
@Override
protected void cleanup() {
Arrays.fill(gotClicks, 0);
@@ -227,8 +201,7 @@ public class HitTestClientArea {
@Override
protected void customizeWindow() {
panel = new JPanel() {
JPanel panel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
@@ -238,14 +211,9 @@ public class HitTestClientArea {
}
};
if (window.getName().equals("JFrame")) {
((JFrame) window).setContentPane(panel);
} else if (window.getName().equals("JDialog")) {
((JDialog) window).setContentPane(panel);
}
panel.setBounds(0, 0, PANEL_WIDTH, PANEL_HEIGHT);
panel.setSize(PANEL_WIDTH, PANEL_HEIGHT);
final int effectiveWidth = window.getWidth() - window.getInsets().left - window.getInsets().right;
panel.setPreferredSize(new Dimension(effectiveWidth, (int) TestUtils.TITLE_BAR_HEIGHT));
panel.setBounds(0, 0, effectiveWidth, (int) TestUtils.TITLE_BAR_HEIGHT);
panel.addMouseListener(new MouseAdapter() {
private void hit() {
titleBar.forceHitTest(true);
@@ -271,6 +239,9 @@ public class HitTestClientArea {
mouseReleased = true;
}
});
window.add(panel);
window.setAlwaysOnTop(true);
}
@Override
@@ -281,24 +252,18 @@ public class HitTestClientArea {
int initialY = window.getLocationOnScreen().y + PANEL_HEIGHT / 2;
for (Integer mask: BUTTON_MASKS) {
robot.waitForIdle();
robot.mouseMove(initialX, initialY);
robot.mousePress(mask);
robot.mouseRelease(mask);
robot.waitForIdle();
MouseUtils.verifyLocationAndClick(robot, window, initialX, initialY, mask);
}
Point initialLocation = window.getLocationOnScreen();
robot.waitForIdle();
robot.mouseMove(initialX, initialY);
MouseUtils.verifyLocationAndMove(robot, window, initialX, initialY);
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
for (int i = 0; i < 10; i++) {
initialX += 3;
initialY += 3;
robot.delay(300);
robot.mouseMove(initialX, initialY);
MouseUtils.verifyLocationAndMove(robot, window, initialX, initialY);
}
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
robot.waitForIdle();

View File

@@ -22,11 +22,9 @@
*/
import com.jetbrains.JBR;
import util.CommonAPISuite;
import util.Task;
import util.TaskResult;
import util.TestUtils;
import util.*;
import javax.swing.*;
import java.awt.AWTException;
import java.awt.Button;
import java.awt.Color;
@@ -53,12 +51,24 @@ import java.util.List;
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=3.0 HitTestNonClientArea
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=3.5 HitTestNonClientArea
* @run main/othervm -Dsun.java2d.uiScale.enabled=true -Dsun.java2d.uiScale=4.0 HitTestNonClientArea
*/
public class HitTestNonClientArea {
public static void main(String... args) {
TaskResult result = CommonAPISuite.runTestSuite(TestUtils.getWindowCreationFunctions(), hitTestNonClientArea);
private static final List<Integer> BUTTON_MASKS = List.of(
InputEvent.BUTTON1_DOWN_MASK,
InputEvent.BUTTON2_DOWN_MASK,
InputEvent.BUTTON3_DOWN_MASK
);
private static final int BUTTON_WIDTH = 80;
private static final int BUTTON_HEIGHT = 40;
public static void main(String... args) {
TaskResult awtResult = CommonAPISuite.runTestSuite(List.of(TestUtils::createFrameWithCustomTitleBar, TestUtils::createDialogWithCustomTitleBar), hitTestNonClientAreaAWT);
TaskResult swingResult = CommonAPISuite.runTestSuite(List.of(TestUtils::createJFrameWithCustomTitleBar, TestUtils::createJFrameWithCustomTitleBar), hitTestNonClientAreaSwing);
TaskResult result = awtResult.merge(swingResult);
if (!result.isPassed()) {
final String message = String.format("%s FAILED. %s", MethodHandles.lookup().lookupClass().getName(), result.getError());
throw new RuntimeException(message);
@@ -66,15 +76,7 @@ public class HitTestNonClientArea {
}
private static final Task hitTestNonClientArea = new Task("Hit test non-client area") {
private static final List<Integer> BUTTON_MASKS = List.of(
InputEvent.BUTTON1_DOWN_MASK,
InputEvent.BUTTON2_DOWN_MASK,
InputEvent.BUTTON3_DOWN_MASK
);
private static final int BUTTON_WIDTH = 80;
private static final int BUTTON_HEIGHT = 40;
private static final Task hitTestNonClientAreaAWT = new AWTTask("Hit test non-client area AWT") {
private final boolean[] gotClicks = new boolean[BUTTON_MASKS.size()];
private Button button;
@@ -128,6 +130,98 @@ public class HitTestNonClientArea {
window.add(panel);
}
@Override
public void test() throws AWTException {
Robot robot = new Robot();
int initialX = button.getLocationOnScreen().x + button.getWidth() / 2;
int initialY = button.getLocationOnScreen().y + button.getHeight() / 2;
for (Integer mask: BUTTON_MASKS) {
MouseUtils.verifyLocationAndClick(robot, window, initialX, initialY, mask);
}
Point initialLocation = window.getLocationOnScreen();
robot.waitForIdle();
MouseUtils.verifyLocationAndMove(robot, window, initialX, initialY);
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
for (int i = 0; i < 10; i++) {
initialX += 3;
initialY += 3;
robot.delay(300);
MouseUtils.verifyLocationAndMove(robot, window, initialX, initialY);
}
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
robot.waitForIdle();
Point newLocation = window.getLocationOnScreen();
passed = initialLocation.x < newLocation.x && initialLocation.y < newLocation.y;
if (!passed) {
System.out.println("Window location was changed");
}
for (int i = 0; i < BUTTON_MASKS.size(); i++) {
if (!gotClicks[i]) {
err("Mouse click to button no " + (i+1) + " was not registered");
}
}
}
};
private static final Task hitTestNonClientAreaSwing = new SwingTask("Hit test non-client area Swing") {
private final boolean[] gotClicks = new boolean[BUTTON_MASKS.size()];
private JButton button;
@Override
protected void cleanup() {
Arrays.fill(gotClicks, false);
titleBar = null;
}
@Override
public void prepareTitleBar() {
titleBar = JBR.getWindowDecorations().createCustomTitleBar();
titleBar.setHeight(TestUtils.TITLE_BAR_HEIGHT);
}
@Override
public void customizeWindow() {
button = new JButton();
button.setBackground(Color.CYAN);
button.setSize(BUTTON_WIDTH, BUTTON_HEIGHT);
MouseAdapter adapter = new MouseAdapter() {
private void hit() {
titleBar.forceHitTest(false);
}
@Override
public void mouseClicked(MouseEvent e) {
hit();
if (e.getButton() >= 1 && e.getButton() <= 3) {
gotClicks[e.getButton() - 1] = true;
}
}
@Override
public void mousePressed(MouseEvent e) {
hit();
}
@Override
public void mouseReleased(MouseEvent e) {
hit();
}
};
button.addMouseListener(adapter);
button.addMouseMotionListener(adapter);
Panel panel = new Panel();
panel.setBounds(300, 20, 100, 50);
panel.add(button);
window.add(panel);
window.setAlwaysOnTop(true);
}
@Override
public void test() throws AWTException {
Robot robot = new Robot();

View File

@@ -0,0 +1,41 @@
package util;
import java.awt.*;
public class MouseUtils {
public static void verifyLocationAndMove(Robot robot, Window window, int x, int y) {
verifyLocation(window, x, y);
robot.waitForIdle();
robot.mouseMove(x, y);
robot.delay(50);
}
public static void verifyLocationAndClick(Robot robot, Window window, int x, int y, int mask) {
verifyLocation(window, x, y);
robot.waitForIdle();
robot.mouseMove(x, y);
robot.delay(50);
robot.mousePress(mask);
robot.delay(50);
robot.mouseRelease(mask);
}
private static void verifyLocation(Window window, int x, int y) {
int x1 = window.getLocationOnScreen().x + window.getInsets().left;
int x2 = x1 + window.getBounds().width - window.getInsets().right;
int y1 = window.getLocationOnScreen().y + window.getInsets().top;
int y2 = y1 + window.getBounds().height - window.getInsets().bottom;
boolean isLocationValid = (x1 < x && x < x2 && y1 < y && y < y2);
if (!isLocationValid) {
throw new RuntimeException("Coordinates (" + x + ", " + y + ") is outside of clickable area");
}
if (!window.isVisible()) {
throw new RuntimeException("Window isn't visible. Can't click to the area");
}
}
}

View File

@@ -94,9 +94,9 @@ abstract public class Task {
}
protected void disposeUI() {
cleanup();
titleBar = null;
window.dispose();
cleanup();
}
protected void cleanup() {