GP-5149 - Fix for toggling visibility of component providers

This commit is contained in:
dragonmacher 2024-11-27 16:32:12 -05:00
parent 7ec765c854
commit dbca3b35cd
4 changed files with 44 additions and 54 deletions

View file

@ -608,6 +608,7 @@ abstract class OperandFieldHelper extends FieldFactory {
}
private ColorStyleAttributes getOpAttributes(Object opObject, Instruction inst, int opIndex) {
if (opObject instanceof String) {
return getOpAttributes(inst, opIndex, inst.getProgram());
}

View file

@ -1076,6 +1076,10 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
private class ShowProviderAction extends DockingAction {
/** Number of milliseconds to track user requests */
private static final int TIME_WINDOW = 2000;
private SortedSet<Long> clickTimes = new TreeSet<>();
ShowProviderAction(boolean supportsKeyBindings) {
super(name, owner,
supportsKeyBindings ? KeyBindingType.SHARED : KeyBindingType.UNSUPPORTED);
@ -1100,19 +1104,37 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
@Override
public void actionPerformed(ActionContext context) {
if (isShowing()) {
boolean isFrustrated = isFrustrated();
boolean isFocused = isFocused();
if (isFocused && !isFrustrated) {
// the user has decided to hide this component and is not madly clicking
setVisible(false);
return;
}
DockingWindowManager myDwm = DockingWindowManager.getInstance(getComponent());
if (myDwm == null) {
// this can happen when the tool loses focus
dockingTool.showComponentProvider(ComponentProvider.this, true);
return;
}
boolean emphasize = getComponent().isShowing() && isFrustrated;
Tool tool = getTool();
DockingWindowManager myDwm = tool.getWindowManager();
myDwm.showComponent(ComponentProvider.this, true, emphasize);
}
myDwm.showComponent(ComponentProvider.this, true, true);
private boolean isFrustrated() {
long time = System.currentTimeMillis();
clickTimes.add(time);
// grab all click times within the time window
long secondsAgo = time - TIME_WINDOW;
SortedSet<Long> recentClicks = clickTimes.tailSet(secondsAgo);
clickTimes.retainAll(recentClicks); // drop old click times
int clickCount = recentClicks.size();
return clickCount > 2; // rapid clicking within the time window
}
private boolean isFocused() {
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
Component focusOwner = kfm.getFocusOwner();
JComponent myComponent = getComponent();
return focusOwner != null && SwingUtilities.isDescendingFrom(focusOwner, myComponent);
}
@Override

View file

@ -107,6 +107,15 @@ public class DockableHeader extends GenericHeader
super.setSelected(hasFocus);
}
@Override
public void dispose() {
if (focusAnimator != null) {
focusAnimator.stop();
focusAnimator = null;
}
super.dispose();
}
void installRenameAction(MouseListener listener) {
titlePanel.installRenameAction(listener);
}

View file

@ -84,7 +84,6 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
private PlaceholderManager placeholderManager;
private LRUSet<ComponentPlaceholder> lastFocusedPlaceholders = new LRUSet<>(20);
private ActivatedInfo activatedInfo = new ActivatedInfo();
private ComponentPlaceholder focusedPlaceholder;
private ComponentPlaceholder nextFocusedPlaceholder;
private ComponentProvider defaultProvider;
@ -959,7 +958,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
placeholder.show(visibleState);
if (visibleState) {
movePlaceholderToFront(placeholder, false);
movePlaceholderToFront(placeholder, shouldEmphasize);
if (placeholder.getNode() == null) {
root.addToNewWindow(placeholder);
}
@ -978,12 +977,10 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
private void movePlaceholderToFront(ComponentPlaceholder placeholder, boolean emphasisze) {
placeholder.toFront();
if (emphasisze) {
activatedInfo.activated(placeholder);
}
toFront(root.getWindow(placeholder));
if (emphasisze) {
placeholder.emphasize();
}
}
/**
@ -1448,10 +1445,6 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
focusedPlaceholder.setSelected(false);
}
// Activating placeholders is done to help users find widgets hiding in plain sight.
// Assume that the user is no longer seeking a provider if they are clicking around.
activatedInfo.clear();
focusedPlaceholder = placeholder;
// put the last focused placeholder at the front of the list for restoring focus work later
@ -2518,39 +2511,4 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
});
}
//==================================================================================================
// Inner Classes
//==================================================================================================
/**
* A class that tracks placeholders that are activated (brought to the front). If a placeholder
* is activated too frequently, this class will emphasize that window, under the assumption that
* the user doesn't see the window.
*/
private class ActivatedInfo {
private long lastCalledTimestamp;
private ComponentPlaceholder lastActivatedPlaceholder;
void activated(ComponentPlaceholder placeholder) {
if (lastActivatedPlaceholder == placeholder) {
// repeat call--see if it was quickly called again (a sign of confusion/frustration)
long elapsedTime = System.currentTimeMillis() - lastCalledTimestamp;
if (elapsedTime < 3000) { // somewhat arbitrary time window
placeholder.emphasize();
}
}
else {
this.lastActivatedPlaceholder = placeholder;
}
lastCalledTimestamp = System.currentTimeMillis();
}
void clear() {
lastActivatedPlaceholder = null;
lastCalledTimestamp = 0;
}
}
}