From 54f0995d85515f89f042b281dd056e2aa68feb9d Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Thu, 5 Sep 2024 17:51:57 -0400 Subject: [PATCH] Fixed popup window placement issue --- .../gui/MemorySearchControlPanel.java | 14 ++++++++--- .../java/docking/widgets/PopupWindow.java | 24 ++++++++++++++----- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemorySearchControlPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemorySearchControlPanel.java index 389a6ff228..1fc4e88de5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemorySearchControlPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemorySearchControlPanel.java @@ -43,6 +43,7 @@ import ghidra.util.Swing; import ghidra.util.layout.PairLayout; import ghidra.util.layout.VerticalLayout; import ghidra.util.timer.GTimer; +import ghidra.util.timer.GTimerMonitor; /** * Internal panel of the memory search window that manages the controls for the search feature. This @@ -62,8 +63,10 @@ class MemorySearchControlPanel extends JPanel { private List> initialSearchButtonStates; private List> combinerSearchButtonStates; private JComboBox formatComboBox; + private PopupWindow popup; private String errorMessage; + private GTimerMonitor clearInputMonitor; MemorySearchControlPanel(MemorySearchProvider provider, SearchGuiModel model, SearchHistory history) { @@ -296,7 +299,7 @@ class MemorySearchControlPanel extends JPanel { if (errorMessage == null) { return; } - errorMessage = null; + DockingUtils.setTipWindowEnabled(false); Point location = searchInputField.getLocation(); @@ -305,13 +308,15 @@ class MemorySearchControlPanel extends JPanel { JToolTip tip = new JToolTip(); tip.setTipText(errorMessage); + errorMessage = null; if (popup != null) { popup.dispose(); + clearInputMonitor.cancel(); } popup = new PopupWindow(tip); - popup.showPopup(searchInputField, location, true); - GTimer.scheduleRunnable(1500, this::clearInputError); + popup.showPopup(searchInputField.getParent(), location, true); + clearInputMonitor = GTimer.scheduleRunnable(2000, this::clearInputError); Toolkit.getDefaultToolkit().beep(); } @@ -321,6 +326,9 @@ class MemorySearchControlPanel extends JPanel { PopupWindow.hideAllWindows(); if (popup != null) { popup.dispose(); + popup = null; + clearInputMonitor.cancel(); + clearInputMonitor = null; } } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/PopupWindow.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/PopupWindow.java index 667bfa7545..b23ae5b4e4 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/PopupWindow.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/PopupWindow.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -264,7 +264,18 @@ public class PopupWindow { * Shows this popup window unless popups are disabled as reported by * {@link DockingUtils#isTipWindowEnabled()}. If {@code forceShow} is true, then the popup * will be shown regardless of the state returned by {@link DockingUtils#isTipWindowEnabled()}. - * @param component the component for the popup + *

+ * Note: the component passed in is the component to which the {@code location} the location + * belongs. In the example below, the component used to get the location is to the component + * passed to this method. This is because the location is relative to the parent's coordinate + * space. Thus, when calling this method, make sure to use the correct component. + *

+	 * Point location = textField.getLocation(); // this is relative to the text field's parent
+	 * Component parent = textField.getParent();
+	 * PopupWindow.showPopup(parent, location, true);
+	 * 
+ * + * @param component the component whose coordinate space the location belongs * @param location the location to show the popup * @param forceShow true to show the popup even popups are disabled application-wide */ @@ -395,14 +406,14 @@ public class PopupWindow { Rectangle newArea = new Rectangle(keepVisibleAea); Point point = newArea.getLocation(); - SwingUtilities.convertPointToScreen(point, source.getParent()); + SwingUtilities.convertPointToScreen(point, source); newArea.setLocation(point); return newArea; } // for debug private void installDebugPainter(Rectangle keepVisibleArea) { -// + // GGlassPane glassPane = GGlassPane.getGlassPane(source); // for (GGlassPanePainter p : painters) { // glassPane.removePainter(p); @@ -439,7 +450,8 @@ public class PopupWindow { // show where the user hovered if (location != null) { Point p = new Point(location); - p = SwingUtilities.convertPoint(source.getParent(), p.x, p.y, glassPane); + p = SwingUtilities.convertPoint(source, p.x, p.y, glassPane); + g.setColor(Palette.RED.withAlpha(alpha)); int offset = 10; g.fillRect(p.x - offset, p.y - offset, (offset * 2), (offset * 2));